java.lang.RuntimeException: error:03000068:bignum

2020-05-03 12:17发布

问题:

I want to implement RSA encryption with public and private key in the android. Implementation I have done is as below.

public static String enccriptData(String dataToEncrypt)
{
    try {
        String publicExponentString = "AQAB";
        String PUBLIC_KEY = "BgIAAACkAABSU0ExAAQAAAEAAQBJGj09Gbyl7BS/8MytvjBUUfaktW984VHHW4lSI9y2OwaeOq4qqSD6IOHU9HL/QtwZ+wELq28eAOQSnr11hifMf6zWjIsCBHOEpLNJjL3wxjl7dUBEGMJOeZj2rmcf8v7lP/rpAtO/G8wKXhAIKLIFxcChkXwQKbQbHQ/FtX2bwg=="

        byte[] modulusBytes = Base64.decodeBase64(PUBLIC_KEY);
        byte[] exponentBytes = Base64.decodeBase64(publicExponentString);
        BigInteger modulus = new BigInteger(1, modulusBytes);
        BigInteger publicExponent = new BigInteger(1, exponentBytes);

        RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, publicExponent);
        KeyFactory fact = null;
        fact = KeyFactory.getInstance("RSA");

        PublicKey pubKey = fact.generatePublic(rsaPubKey);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);

        String token = dataToEncrypt + ":" + String.valueOf(getCurrentDateTimeTicks());

        byte[] plainBytes = token.getBytes("UTF-16LE");
        byte[] cipherData = cipher.doFinal(plainBytes);
        String encryptedStringBase64 = Base64.encodeBase64String(cipherData);
        return encryptedStringBase64;
    }catch (Exception e){
        e.printStackTrace();
    }

    return null;
}

private static long getCurrentDateTimeTicks(){
    long TICKS_AT_EPOCH = 621355968000000000L;
    long tick = System.currentTimeMillis()*10000 + TICKS_AT_EPOCH;
    return tick;
}

This works fine when I run this code as a Java file. It encrypts the data as expected. But, when I use this code in the android application, it gives below error.

java.lang.RuntimeException: error:03000068:bignum routines:OPENSSL_internal:CALLED_WITH_EVEN_MODULUS
 at com.android.org.conscrypt.NativeCrypto.RSA_public_encrypt(Native Method)
 at com.android.org.conscrypt.OpenSSLCipherRSA$DirectRSA.doCryptoOperation(OpenSSLCipherRSA.java:371)
 at com.android.org.conscrypt.OpenSSLCipherRSA.engineDoFinal(OpenSSLCipherRSA.java:292)
 at javax.crypto.Cipher.doFinal(Cipher.java:1741)

Equivalent C# code is as below

public string GenerateToken()
{
    var completeToken = string.Format("{0}:{1}", _dataToEncrypt, DateTime.UtcNow.Ticks);
    var encryptedToken = EncryptionHelper.Encrypt(_publicKey, completeToken);
    var token = Convert.ToBase64String(encryptedToken);
    return token;
}

public static byte[] Encrypt(string publicKey, string data)
{
    var cspParams = new CspParameters { ProviderType = 1 };
    var rsaProvider = new RSACryptoServiceProvider(cspParams);

    rsaProvider.ImportCspBlob(Convert.FromBase64String(publicKey));

    var plainBytes = Encoding.UTF8.GetBytes(data);
    var encryptedBytes = rsaProvider.Encrypt(plainBytes, false);

    return encryptedBytes;
}

Ref link Translating C# RSACryptoServiceProvider into JAVA Code