I'm trying to port our android mobile app to Flutter. It was written in Java. However, there is this part where I need to encrypt the login credential and card details with RSA encryption before posting to the server which I've not been able to get right.
I've tried several flutter packages which doesn't work. According to the Java developer, there is a public key which is base64 encoded that needs to be used in encrypting the password.
Here is the Java code
public static String Encrypt(String plaintext, String publicKey ) throws Exception {
try
{
if(StringUtils.isEmpty(plaintext)) return "";
byte[] modulusBytes = Base64.decode(publicKey.getBytes("UTF-8"),Base64.DEFAULT);
byte[] exponentBytes = Base64.decode("AQAB".getBytes("UTF-8"),Base64.DEFAULT);
BigInteger modulus = new BigInteger(1, modulusBytes );
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPubKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] plainBytes = new String(plaintext).getBytes("UTF-8");
byte[] cipherData = cipher.doFinal( plainBytes );
String outputEncrypted = Base64.encodeToString(cipherData,Base64.NO_WRAP);
return outputEncrypted;
}catch (Exception ex)
{
Log.i("Exception", ex.getMessage());
throw ex;
}
}
I'll appreciate if I can get any help to convert this to dart so I can use it in the flutter code.
UPDATE
I tried @Richard Heap pointycastle encryption which seems to work fine but the server was unable to decrypt the string. Exception thrown
Interop+AppleCrypto+AppleCFErrorCryptographicException: The operation couldn’t be completed. (OSStatus error -2147415994 - CSSMERR_CSP_INVALID_DATA)
at Interop.AppleCrypto.ExecuteTransform(SecKeyTransform transform)
at Interop.AppleCrypto.RsaDecrypt(SafeSecKeyRefHandle privateKey, Byte[] data, RSAEncryptionPadding padding)
at System.Security.Cryptography.RSAImplementation.RSASecurityTransforms.Decrypt(Byte[] data, RSAEncryptionPadding padding)
at System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP)
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: The parameter is incorrect
at Internal.NativeCrypto.CapiHelper.DecryptKey(SafeKeyHandle safeKeyHandle, Byte[] encryptedData, Int32 encryptedDataLength, Boolean fOAEP, Byte[]& decryptedData)
at System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP
The decryption method on the server is written with C#
UPDATE 2
Finally got this to work after hours of googling I landed on this github issue on PointyCastle and the solution by duncanhoggan. Turned out I just needed to use PKCS1Encoding.
var pubKey = RSAPublicKey(modulus, exponent);
var cipher = PKCS1Encoding(RSAEngine());
cipher.init(true, PublicKeyParameter<RSAPublicKey>(pubKey));
Uint8List output = cipher.process(utf8.encode(text));
var base64EncodedText = base64Encode(output);
return base64EncodedText;
@Richard Heap, thanks for helping.