bcgit / pc-dart

Pointy Castle - Dart Derived Bouncy Castle APIs
MIT License
241 stars 125 forks source link

Unable to decrypt RSA encrypted data #146

Closed arnirichard closed 2 years ago

arnirichard commented 2 years ago

I am generating asymmetric key in C# and encrypting in Flutter using the public key, but decryption back fails in C#

in C#:

RSACryptoServiceProvider algorithm = new RSACryptoServiceProvider(2048); var param = algorithm.ExportParameters(false); byte[] modulus = param.Modulus; byte[] exponent = param.Exponent;

modulus and exponent (65537) are used to create public key in Flutter, for encryption of list of 32 bytes (data), the resulting data is 256 bytes:

RSAPublicKey publickey = RSAPublicKey(readBytes(Uint8List.fromList(modulus)), readBytes(Uint8List.fromList(exponent)); AsymmetricBlockCipher cipher = PKCS1Encoding(RSAEngine()); cipher.init(true, PublicKeyParameter<RSAPublicKey>(publicKey)); Uint8List encryptedData = cipher.process(data)

Uint8List converted to BigInt using

static BigInt readBytes(Uint8List bytes) { BigInt read(int start, int end) { if (end - start <= 4) { int result = 0; for (int i = end - 1; i >= start; i--) { result = result * 256 + bytes[i]; } return new BigInt.from(result); } int mid = start + ((end - start) >> 1); var result = read(start, mid) + read(mid, end) * (BigInt.one << ((mid - start) * 8)); return result; } return read(0, bytes.length); }

In C# I try to decrypt the encrypted data (byte array) using the original RSACryptoServiceProvider (algorithm)

algorithm .Decrypt(encryptedData , RSAEncryptionPadding.Pkcs1);

which results in exception:

System.Security.Cryptography.CryptographicException HResult=0x80070057 Message=The parameter is incorrect.

Source=mscorlib StackTrace: at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr) at System.Security.Cryptography.RSACryptoServiceProvider.DecryptKey(SafeKeyHandle pKeyContext, Byte[] pbEncryptedKey, Int32 cbEncryptedKey, Boolean fOAEP, ObjectHandleOnStack ohRetDecryptedKey) at System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP) at System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[] data, RSAEncryptionPadding padding) at Logis.Utilities.Sockets.TPCv2.Internal.KeySet.Decrypt(RSACryptoServiceProvider aSK) in C:\Logis\TFS\Logis Tools\Logis.Utilities\Logis.Utilities\Sockets\TPCv2\Internal\KeySet.cs:line 40

I believe the problem is simple, but I can't figure it out. Can someone help?

I am using pointycastle: 3.4.0 and also tried pc_steelcrypt: 1.1.1

licy183 commented 2 years ago

Hello. I could encrypt and decrypt data properly between C# and pointycastle. Following are my codes and outputs.

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Stream steam = Console.OpenStandardInput();
            Console.SetIn(new StreamReader(steam, Encoding.Default, false, 5000));
            RSACryptoServiceProvider algorithm = new RSACryptoServiceProvider(2048);
            var param = algorithm.ExportParameters(false);
            Console.WriteLine("Modulus in hex: " + BitConverter.ToString(param.Modulus).Replace("-", ""));
            Console.WriteLine("Exponent in hex: " + BitConverter.ToString(param.Exponent).Replace("-", ""));
            Console.Write("Input the encrypted data in base64: ");
            string str = Console.ReadLine();
            byte[] encryptData = Convert.FromBase64String(str);
            byte[] decode = algorithm.Decrypt(encryptData, RSAEncryptionPadding.Pkcs1);
            Console.WriteLine("Data in hex:" + BitConverter.ToString(decode).Replace("-", ""));
        }
    }
}
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';
import 'package:convert/convert.dart';

import 'package:pointycastle/export.dart';

void main() {
  final random = Random();
  final data =
      Uint8List.fromList(List<int>.generate(32, (_) => random.nextInt(256)));
  print('Data (in hex): ' + hex.encode(data));
  var m = BigInt.parse(
    'Put the hex modulus here',
    radix: 16,
  );
  var publickey = RSAPublicKey(m, BigInt.from(65537));
  AsymmetricBlockCipher cipher = PKCS1Encoding(RSAEngine());
  cipher.init(true, PublicKeyParameter<RSAPublicKey>(publickey));
  var encryptedData = cipher.process(data);
  print('The encrypted data (in base64): ' + base64.encode(encryptedData));
}
Modulus in hex: AAECF2246B2C4D5B9C505D72DEBD26FC62B7B18DAB42CA248B28B008C36D35945B33839997AEECD5176FFEC3C6B9BA8F8ABA2BB157C2927CB869A78DB605D8401CFA0AC4F813ABEAB583235EF266D9CD1A3A5A99D19BB314B5E1E6044F27CD4D6775167D0AA275C545193A9FA7863F5232FAFF6842561AFC32D56C1C4D28B03E32DB3C4F6B8C942CA68A6A957A47D1F9416D5E22BFF5A0E8BE51CD16FDEB755C2CFB01710E47380F56B9C07E6019D96300F21096E16E81C5B0396A45C3573AA79B7FB34F97260226E0AE5EF341585F85BE83D85378980457D7A197F3457918EAB7B11D8AE6172EF7A512CF59748E44B1C73A0504BC491B4074B2B6179D60E9FD
Exponent in hex: 010001
Input the encrypted data in base64: ZseP0ag5VdoShfSamDmUkys1Lo08oiPSbUdNr14LRDzrC5hn9xmyt0nlS0sJIRB8zzk4XEiYkX8utxDhhkTybReNZTqqQvTG/8fjilCZ2kHANYS4pJshhdrGTnOSmkL410LxklNF1PpKQHBS6E3nV5Z7ALrquN6U84AfVYpOvA5EB60c1rLg0V6Ef/MSKdMpaJoJwNNYIvLItbG2ngXLy2rBynlOvX6zdOxssAtLND1WKNFhL3AVSD718rLp8BkWrV2dVv0CS/tsxxkEEsrODGRuspS1DbNYiwcf+6ya/XhrTOFJyzN25eJCwY3slM1iO/sE6CM3o33YRSglawO8kg==
Data in hex:7D313D75AA2CB2A866CF3F40AC32AF9510E476799BEB29E5AF2C134CA2F65D46
Data (in hex): 7d313d75aa2cb2a866cf3f40ac32af9510e476799beb29e5af2c134ca2f65d46
The encrypted data (in base64): ZseP0ag5VdoShfSamDmUkys1Lo08oiPSbUdNr14LRDzrC5hn9xmyt0nlS0sJIRB8zzk4XEiYkX8utxDhhkTybReNZTqqQvTG/8fjilCZ2kHANYS4pJshhdrGTnOSmkL410LxklNF1PpKQHBS6E3nV5Z7ALrquN6U84AfVYpOvA5EB60c1rLg0V6Ef/MSKdMpaJoJwNNYIvLItbG2ngXLy2rBynlOvX6zdOxssAtLND1WKNFhL3AVSD718rLp8BkWrV2dVv0CS/tsxxkEEsrODGRuspS1DbNYiwcf+6ya/XhrTOFJyzN25eJCwY3slM1iO/sE6CM3o33YRSglawO8kg==
arnirichard commented 2 years ago

Thanks, I found out that the converter function readBytes was incorrect. A correct implementation is below

static BigInt decodeBigInt(List<int> bytes) { BigInt result = new BigInt.from(0); for (int i = 0; i < bytes.length; i++) { result += new BigInt.from(bytes[bytes.length - i - 1]) << (8 * i); } return result; }