PointyCastle / pointycastle

Moved into the Bouncy Castle project: https://github.com/bcgit/pc-dart
MIT License
270 stars 76 forks source link

Failed to decrypt RSA encryption #158

Open rickyazhari opened 5 years ago

rickyazhari commented 5 years ago

hi, i do RSA encryption with pointy castle and always failed to decrypted back.

btw, decrypt process is in different environment using PHP

here's my code :

BigInt modulus =  BigInt.parse(key,radix: 16);
    BigInt exponent = BigInt.from(65537);
    RSAPublicKey pubKey = new RSAPublicKey(modulus, exponent);
    AsymmetricKeyParameter<RSAPublicKey>  params = PublicKeyParameter(pubKey);
     //RSAEngine engine = new RSAEngine()..init(true, params);
    AsymmetricBlockCipher cipher = new AsymmetricBlockCipher("RSA/PKCS1")..init(true, params);
    Uint8List  plainText = Uint8List.fromList(plain.codeUnits);
    Uint8List encryptText =  cipher.process(plainText);
    List<String> hexes = "0123456789ABCDEF".split("");
    StringBuffer buffer = new StringBuffer(2*encryptText.length);
    for(int b in encryptText){
      buffer.write(hexes[(b & 0xF0) >> 4]);
      buffer.write(hexes[(b &0x0F)]);
    }
    return buffer.toString();

here's my flutter doctor

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel beta, v0.9.4, on Mac OS X 10.14 18A391, locale en-ID)
[✓] Android toolchain - develop for Android devices (Android SDK 27.0.3)
[!] iOS toolchain - develop for iOS devices (Xcode 10.0)
    ! CocoaPods out of date (1.5.0 is recommended).
        CocoaPods is used to retrieve the iOS platform side's plugin code that responds to your plugin usage on the Dart side.
        Without resolving iOS dependencies with CocoaPods, plugins will not work on iOS.
        For more info, see https://flutter.io/platform-plugins
      To upgrade:
        brew upgrade cocoapods
        pod setup
[✓] Android Studio (version 3.2)
[!] VS Code (version 1.28.2)
[✓] Connected devices (1 available)

is there something wrong in my encryption process ?

duncanhoggan commented 5 years ago

@rickyazhari This is what i use for my pkcs1 encrypt, i'm using a C# based server implementation for decrypting and all is good. I'm passing in the modulus and exponent in as strings.

var text = "Your message here"
var pubKey = RSAPublicKey(BigInt.parse(modulus), BigInt.parse(exponent))
var cipher = PKCS1Encoding(RSAEngine());
cipher.init(true, PublicKeyParameter<RSAPublicKey>(pubKey));
Uint8List output = cipher.process(utf8.encode(text));
var base64EncodedText = base64Encode(output);

Give that a go and see if you get the same results.

rickyazhari commented 5 years ago

hai @duncanhoggan thanks for advice. i already follow your code for encryption. unfortunately it's cannot decrypted as well. here's my code

RSAPublicKey pubkey = new RSAPublicKey(BigInt.parse(key,radix: 16), BigInt.parse("65537"));
    var cipher = PKCS1Encoding(new RSAEngine());
    cipher.init(true, PublicKeyParameter<RSAPublicKey>(pubkey));
    var encryptText = cipher.process(Uint8List.fromList(plain.codeUnits));
    List<String> hexes = "0123456789ABCDEF".split("");
    StringBuffer buffer = new StringBuffer(2*encryptText.length);
    for(int b in encryptText){
      buffer.write(hexes[(b & 0xF0) >> 4]);
      buffer.write(hexes[(b &0x0F)]);
    }
    return buffer.toString();

Really thanks, i still figure out where i miss

duncanhoggan commented 5 years ago

Hey, not sure what you plan is but you need the private and public pieces of the key to decrypt if you are using RSA.

Generally... message ---> encrypted using public key ---> transport ---> decrypted using private key ---> message

rickyazhari commented 5 years ago

@duncanhoggan yah Generally such as you wrote in above. But i want just encryption process in client side and decryption in server side.

After some sample there is size different encryption result of native android encryption and flutter with pointy castle which is i've got 259 String length in flutter and 255 String length in native android. After that, flutter encryption result still failed to decrypt when native android is success one.

rickyazhari commented 5 years ago

hi, i do RSA encryption with pointy castle and always failed to decrypted back.

btw, decrypt process is in different environment using PHP

here's my code :

BigInt modulus =  BigInt.parse(key,radix: 16);
    BigInt exponent = BigInt.from(65537);
    RSAPublicKey pubKey = new RSAPublicKey(modulus, exponent);
    AsymmetricKeyParameter<RSAPublicKey>  params = PublicKeyParameter(pubKey);
     //RSAEngine engine = new RSAEngine()..init(true, params);
    AsymmetricBlockCipher cipher = new AsymmetricBlockCipher("RSA/PKCS1")..init(true, params);
    Uint8List  plainText = Uint8List.fromList(plain.codeUnits);
    Uint8List encryptText =  cipher.process(plainText);
    List<String> hexes = "0123456789ABCDEF".split("");
    StringBuffer buffer = new StringBuffer(2*encryptText.length);
    for(int b in encryptText){
      buffer.write(hexes[(b & 0xF0) >> 4]);
      buffer.write(hexes[(b &0x0F)]);
    }
    return buffer.toString();

here's my flutter doctor

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel beta, v0.9.4, on Mac OS X 10.14 18A391, locale en-ID)
[✓] Android toolchain - develop for Android devices (Android SDK 27.0.3)
[!] iOS toolchain - develop for iOS devices (Xcode 10.0)
    ! CocoaPods out of date (1.5.0 is recommended).
        CocoaPods is used to retrieve the iOS platform side's plugin code that responds to your plugin usage on the Dart side.
        Without resolving iOS dependencies with CocoaPods, plugins will not work on iOS.
        For more info, see https://flutter.io/platform-plugins
      To upgrade:
        brew upgrade cocoapods
        pod setup
[✓] Android Studio (version 3.2)
[!] VS Code (version 1.28.2)
[✓] Connected devices (1 available)

is there something wrong in my encryption process ?

ok finally today i solve this problem. With sample test result

i run some test which is turn in to concluded with un-match length crypto text result. the result of crypto text using this method is 259. i use 2048 bit modulus and expect to get 256 crypto text length. and also in crypto text i found static value in front after i turn the result in to hex. ex :

plain text : pointycastle chiper text (HEX) : 256B360A8AF02823E084763A16727517B9741AEB562399B36743E995B92A3599C93FE4BEE64935CB670FBFCE8BB27372282D36A316AE750D72840CC0358C556F737EC11726F50F649C69B32A892366723DE8B59FF0F16ACBC57025CDCC6C498A58F17B66940F659C64A8172597A6CA53749F243EA68E3116F0560DD42EAAA75F9C2

plain text : password123 chiper text(HEX) : 256B8A2F63F393EC314E079029E170507BD5A4F66C6E042FC01E7889F14A200C25E8266122DDBF489BCDD505DE384E1F8061A554A3E041F4A4C78ED7AA515E866952B2522E0098842C7C99C61B20B575DDF3E1DC35696DCD471CB7C6D101D65303C7F04E5D00CCBEA9F1BF296A1C0A230016F20C544BE324724AF183401C1B9B7C0

plain text : github321 chiper text(HEX) : 256C60E4E493B4AC600FCD4579F06C55ABEFB4A7089F312BA1A29FA6FE3DA8A876D97142D754344AD73B5D7B1960C0B734A23AD876C7E87575AF25EB43E7461A398C082B69ABC14F0150A4BD53814AA928FEEE62AAD720E14E6372749C45C24039D98E30C028EBD3377780353425F713700556A36C896D873590AA7BF6E82B1388B

so i must remove 3 values in front of chiper text value and chiper text succesfully decrypted back.

thanks for cooperating this issue. please kindly check about that. we can close this issue and look for pointy-castle update

duncanhoggan commented 5 years ago

@rickyazhari firstly a side note you are using the older reflection based cipher initialisation. Try changing your init to the following.

AsymmetricBlockCipher cipher = PKCS1Encoding(RSAEngine());
cipher.init(true, PublicKeyParameter<RSAPublicKey>(pubKey));

The main issue here is your conversion from Uint8List to hex String.

I did the same conversion using the Hex package (shout out the @stevenroose for maintaining this one too)HEX.encode(encryptText); and the output was correct.

rickyazhari commented 5 years ago
String bufferToHex(Uint8List data){
    List<String> hexLib = "0123456789ABCDEF".split("");
    StringBuffer buffer = StringBuffer(2*data.length);
    for(int dt in data){
      buffer.write(hexLib[(dt & 0xF0) >> 4]);
      buffer.write(hexLib[(dt &0x0F)]);
    }
    return buffer.toString();
  }

I make hex conversion my self. it typically general conversion used to convert byte into hex string. I think that's not the main problem. But, I will try with hex library. and such as you suggested.

duncanhoggan commented 5 years ago

@rickyazhari I tested your code again and the hex conversion came out wrong...

var test1 = bufferToHex(Uint8List.fromList([0, 0, 0, 0]));

returns "800000000"

var test2 = bufferToHex(Uint8List.fromList([255, 255, 255, 255]));

returns "8FFFFFFFF"

Test it for yourself and you will come to the same conclusion. Feel free to close the issue when you discover this 👍

rickyazhari commented 5 years ago

@duncanhoggan yah you right. I already test with hex library. I think it's already solve now. We can close this issue.

lets-swapcode commented 5 years ago

Can you share function for decrypting using private key ?

duncanhoggan commented 5 years ago

@lets-swapcode rather open a new issue as opposed to clouding this issue.

Bayonle commented 5 years ago

ar text = "Your message here" var pubKey = RSAPublicKey(BigInt.parse(modulus), BigInt.parse(exponent)) var cipher = PKCS1Encoding(RSAEngine()); cipher.init(true, PublicKeyParameter(pubKey)); Uint8List output = cipher.process(utf8.encode(text)); var base64EncodedText = base64Encode(output);

I'd been battling this for weeks. Your solution worked like charm @duncanhoggan

af2005ce commented 4 years ago

hi C# Server :

public static string RsaEncrypt(string data, string pubkey) { RSAParameters ApublicKey; var pub = GetPublicKeyFromPemFile(pubkey); ApublicKey = pub.ExportParameters(false); RSAParameters result = new RSAParameters(); result.Modulus = ApublicKey.Modulus; result.Exponent = ApublicKey.Exponent; System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); byte[] DataToEncrypt = encoding.GetBytes(data); byte[] encryptedData;

        using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(2048))
        {
            RSA.ImportParameters(result);
            encryptedData = RSA.Encrypt(DataToEncrypt, true);
        }
        return Convert.ToBase64String(encryptedData);
    }

Dart Client :

AsymmetricKeyPair rsaGenerateKeyPair({int bitStrength = 2048}) { var keyParams = new RSAKeyGeneratorParameters(BigInt.parse('65537'), bitStrength, 12); var secureRandom = new FortunaRandom(); var random = new Random.secure(); List seeds = []; for (int i = 0; i < 32; i++) { seeds.add(random.nextInt(255)); } secureRandom.seed(new KeyParameter(new Uint8List.fromList(seeds))); var rngParams = new ParametersWithRandom(keyParams, secureRandom); var k = new RSAKeyGenerator(); k.init(rngParams);

return k.generateKeyPair(); }

encodePublicKeyToPem(RSAPublicKey publicKey) { var algorithmSeq = new ASN1Sequence(); var algorithmAsn1Obj = new ASN1Object.fromBytes(Uint8List.fromList([0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1, 0x1, 0x1])); var paramsAsn1Obj = new ASN1Object.fromBytes(Uint8List.fromList([0x5, 0x0])); algorithmSeq.add(algorithmAsn1Obj); algorithmSeq.add(paramsAsn1Obj);

var publicKeySeq = new ASN1Sequence(); publicKeySeq.add(ASN1Integer(publicKey.modulus)); publicKeySeq.add(ASN1Integer(publicKey.exponent)); var publicKeySeqBitString = new ASN1BitString(Uint8List.fromList(publicKeySeq.encodedBytes)); var dataBase641 = base64.encode(publicKeySeq.encodedBytes); var dataBase642 = base64.encode(publicKeySeq.elements[1].encodedBytes); var topLevelSeq = new ASN1Sequence(); topLevelSeq.add(algorithmSeq); topLevelSeq.add(publicKeySeqBitString);

var dataBase64 = base64.encode(topLevelSeq.encodedBytes); return """-----BEGIN PUBLIC KEY-----\r\n$dataBase64\r\n-----END PUBLIC KEY-----"""; }

String decrypt(String cipherBase64, PublicKey pubkey,PrivateKey prvkry ) { final encrypter = Encrypter(RSA(publicKey: pubkey, privateKey: prvkry)); return encrypter.decrypt64(cipherBase64); }

this code not work true on dart, please help me