RSA算法适用于Android 4.3但Android 2.3.3崩溃

时间:2014-08-12 12:49:48

标签: java android algorithm encryption rsa

我正在尝试使用带有公钥的RSA算法加密文件(我使用给定的模数和指数构建)。

我的代码适用于Android 4.3,我得到了我所需要的一切。但我试图让它适用于其他Android版本(2.3.3)并且没有办法。它抱怨输入对于RSA密码而言太大了#34; 如果我已经很好地理解了这个理论,那么分组密码大小是相对于publicKey.size()的,所以如果这个从一个版本的Android改为另一个版本,我应该得到相同的结果,不应该这样吗? ?

这是我的代码: 包com.example.rsa_ex;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.RSAPublicKeySpec;
import java.util.Arrays;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;

import android.app.Activity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;

public class MainActivity extends Activity 
{

    private byte[] mKeyModulus = {...};
    private byte[] mKeyExponent = {...};

    private String tag = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String token = "";
        try
        {
            token = readTokenFromFile("token.base64");
        }
        catch (IOException e)
        {
            Log.d(tag, "Failed to open property file");
        }

        byte[] encodedBytes = Base64.encode(token.getBytes(), 0);

        Log.d(tag, "Encrypt Token"+ onEncrypt(encodedBytes));
    }

    public String readTokenFromFile(String fileName) throws IOException  
    {  
        String token = "empty";

        try
        {  
            AssetManager assetManager = getAssets();
            InputStream iS = assetManager.open(fileName);

            byte[] buffer = new byte[iS.available()];    
            iS.read(buffer);  

            ByteArrayOutputStream oS = new ByteArrayOutputStream();  

            oS.write(buffer);  
            token = oS.toString();
            oS.close();  
            iS.close(); 

            Log.d(tag, "token ==> "+token);
        }
        catch (IOException e)
        {
            Log.d(tag, "Failed to open property file");
        }

        return token; 

    } // readTokenFromFile end 
    public String onEncrypt(byte[] token)
    {   
        Log.d(tag,"onEncrypt entry");
        String encryptedTranspherable = "";//null;
        // get the publicKey
        try
        {
            BigInteger m = new BigInteger(mKeyModulus);
            BigInteger e = new BigInteger(mKeyExponent);

            KeyFactory fact = KeyFactory.getInstance("RSA");

            Key pubKey = fact.generatePublic(new RSAPublicKeySpec(m, e));

            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);

            byte[] encrypted = blockCipher(token,cipher);
            encryptedTranspherable = Base64.encodeToString(encrypted, Base64.DEFAULT);
        }
        catch (Exception e) 
        {
            throw new RuntimeException("serialisation error got issue here !! ==>"+ e.getMessage(), e);
        }

        return encryptedTranspherable;
    }// onEncrypt end

    private byte[] blockCipher(byte[] bytes,Cipher cipher) throws IllegalBlockSizeException, BadPaddingException
    {
        Log.d(tag,"ISecurityProvider blockCipher entry");
        Log.d(tag,"ISecurityProvider byteArray =>"+ Arrays.toString(bytes));
        byte[] scrambled = new byte[0];

        // toReturn will hold the total result
        byte[] toReturn = new byte[0];
        int length = 256; 

        // another buffer. this one will hold the bytes that have to be modified in this step
        byte[] buffer = new byte[Math.min(bytes.length, length)];//(bytes.length > length ? length : bytes.length)];
        for (int i=0; i< bytes.length; i++)
        {
            // if we filled our buffer array we have our block ready for de- or encryption
            if ((i > 0) && (i % length == 0))
            {
                Log.d(tag,"ISecurityProvider blockCipher processing block  i ="+i);
                scrambled = cipher.doFinal(buffer);
                toReturn = append(toReturn,scrambled);

                // here we calculate the length of the next buffer required
                int newlength = length;

                // if newlength would be longer than  remaining bytes in the bytes array we shorten it.
                if (i + length > bytes.length) 
                {
                    newlength = bytes.length - i;
                }
                // clean the buffer array
                buffer = new byte[newlength];
            }
            // copy byte into our buffer.
            buffer[i%length] = bytes[i];
        }

        // this step is needed if we had a trailing buffer. should only happen when encrypting.
        // example: we encrypt 110 bytes. 100 bytes per run means we "forgot" the last 10 bytes. they are in the buffer array
        scrambled = cipher.doFinal(buffer);
        // final step before we can return the modified data.
        toReturn = append(toReturn,scrambled);

        return toReturn;
    }

    private byte[] append(byte[] prefix, byte[] suffix)
    {
        byte[] toReturn = new byte[prefix.length + suffix.length];

        int prefixSize = prefix.length;
        int  suffixSize = suffix.length;

        for (int i=0; i< prefixSize; i++)
        {
            toReturn[i] = prefix[i];
        }

        for (int i=0; i< suffixSize; i++)
        {
            toReturn[i+prefixSize] = suffix[i];
        }

        return toReturn;
    }
}

任何建议或建议都非常欢迎。 非常感谢。

1 个答案:

答案 0 :(得分:3)

从Android 4.2增强功能:

  

Cryptography - 修改SecureRandom和Cipher.RSA的默认实现以使用OpenSSL。使用OpenSSL 1.0.1为TLSv1.1和TLSv1.2添加了SSL套接字支持

这意味着他们正在使用其他提供程序,可能还有另一个默认 RSA填充机制。您应始终提供完整的算法字符串,而不是依赖提供程序默认值,例如尝试"RSA/ECB/OAEPWithSHA1AndMGF1Padding"申请新申请,"RSA/ECB/PKCS1Padding"申请与旧图书馆兼容。

请注意,您通常不使用RSA直接加密文件。通常使用随机数据密钥使用例如加密文件。 AES,一种对称密码。然后使用RSA公钥加密该AES密钥,并使用密文发送结果。这样,您可以加密(几乎)任意数量的字节。这称为hybrid cryptography