Convert Java RSA Asymmetric encryption to Flutter Dart
Try this:
import 'dart:math';
import 'dart:convert';
import 'dart:typed_data';
import 'package:convert/convert.dart';
import 'package:pointycastle/api.dart';
import 'package:pointycastle/asymmetric/api.dart';
import 'package:pointycastle/asymmetric/rsa.dart';
String encrypt(String plaintext, String publicKey) {
var modulusBytes = base64.decode(publicKey);
var modulus = BigInt.parse(hex.encode(modulusBytes), radix: 16);
var exponent = BigInt.parse(hex.encode(base64.decode('AQAB')), radix: 16);
var engine = RSAEngine()
..init(
true,
PublicKeyParameter<RSAPublicKey>(RSAPublicKey(modulus, exponent)),
);
//PKCS1.5 padding
var k = modulusBytes.length;
var plainBytes = utf8.encode(plaintext);
var paddingLength = k - 3 - plainBytes.length;
var eb = Uint8List(paddingLength + 3 + plainBytes.length);
var r = Random.secure();
eb.setRange(paddingLength + 3, eb.length, plainBytes);
eb[0] = 0;
eb[1] = 2;
eb[paddingLength + 2] = 0;
for (int i = 2; i < paddingLength + 2; i++) {
eb[i] = r.nextInt(254) + 1;
}
print(plainBytes.length);
print(eb);
return base64.encode(
engine.process(eb),
);
}
ibnhamza
Updated on December 11, 2022Comments
-
ibnhamza over 1 year
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.
-
Richard Heap almost 5 yearsHave you tried pointy castle? Where did you get stuck?
-
-
ibnhamza almost 5 yearsThanks Richard. Heard of PointyCastle but haven't really tried using it. Was thinking dart was gonna have some built in encryption suit. Would try out your solution.
-
ibnhamza almost 5 yearsI didn't have any issue encryption but the server was unable to decrypt my encrypted string. I debugged and it was throwing an exception at the point of decrypting. I've updated my question with the exception.
-
Richard Heap almost 5 yearsDart, by design, has very little built in. This kind of add-on library is added in packages, like pointy castle. Updated the question with PKCSv1.5 padding implementation.
-
Pravin Divraniya over 2 yearsWhat is hex value?
-
Richard Heap over 2 years@PravinDivraniya
hex
is a const value from theconvert
package (note the extra package import) for a hexadecimal codec. -
Hemavathi about 2 yearsdo we have EncodedKeySpec in flutter
-
Hemavathi about 2 years@RichardHeap i m trying to convert java code to flutter please refer stackoverflow.com/questions/70576691/… any help is appreciated