import 'dart:convert';
							 | 
						|
								import 'dart:math';
							 | 
						|
								import 'dart:typed_data';
							 | 
						|
								import 'package:pointycastle/export.dart';
							 | 
						|
								import 'package:asn1lib/asn1lib.dart';
							 | 
						|
								
							 | 
						|
								/*
							 | 
						|
								var rsaKeyHelper = RsaKeyHelper();
							 | 
						|
								var keyPair = rsaKeyHelper.generateRSAkeyPair();
							 | 
						|
								var rsaPub = keyPair.publicKey;
							 | 
						|
								var rsaPriv = keyPair.privateKey;
							 | 
						|
								var cipherText = rsaKeyHelper.rsaEncrypt(rsaPub, Uint8List.fromList('Test Data'.codeUnits));
							 | 
						|
								print(cipherText);
							 | 
						|
								var plainText = rsaKeyHelper.rsaDecrypt(rsaPriv, cipherText);
							 | 
						|
								print(String.fromCharCodes(plainText));
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								List<int> decodePEM(String pem) {
							 | 
						|
								    var startsWith = [
							 | 
						|
								        '-----BEGIN PUBLIC KEY-----',
							 | 
						|
								        '-----BEGIN PUBLIC KEY-----',
							 | 
						|
								        '\n-----BEGIN PUBLIC KEY-----',
							 | 
						|
								        '-----BEGIN PRIVATE KEY-----',
							 | 
						|
								        '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: React-Native-OpenPGP.js 0.1\r\nComment: http://openpgpjs.org\r\n\r\n',
							 | 
						|
								        '-----BEGIN PGP PRIVATE KEY BLOCK-----\r\nVersion: React-Native-OpenPGP.js 0.1\r\nComment: http://openpgpjs.org\r\n\r\n',
							 | 
						|
								    ];
							 | 
						|
								    var endsWith = [
							 | 
						|
								        '-----END PUBLIC KEY-----',
							 | 
						|
								        '-----END PRIVATE KEY-----',
							 | 
						|
								        '-----END PGP PUBLIC KEY BLOCK-----',
							 | 
						|
								        '-----END PGP PRIVATE KEY BLOCK-----',
							 | 
						|
								    ];
							 | 
						|
								    bool isOpenPgp = pem.contains('BEGIN PGP');
							 | 
						|
								
							 | 
						|
								    for (var s in startsWith) {
							 | 
						|
								        if (pem.startsWith(s)) {
							 | 
						|
								            pem = pem.substring(s.length);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    for (var s in endsWith) {
							 | 
						|
								        if (pem.endsWith(s)) {
							 | 
						|
								            pem = pem.substring(0, pem.length - s.length);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (isOpenPgp) {
							 | 
						|
								        var index = pem.indexOf('\r\n');
							 | 
						|
								        pem = pem.substring(0, index);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    pem = pem.replaceAll('\n', '');
							 | 
						|
								    pem = pem.replaceAll('\r', '');
							 | 
						|
								
							 | 
						|
								    return base64.decode(pem);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								class RsaKeyHelper {
							 | 
						|
								
							 | 
						|
								    // Generate secure random sequence for seed
							 | 
						|
								    SecureRandom secureRandom() {
							 | 
						|
								        var secureRandom = FortunaRandom();
							 | 
						|
								        var random = Random.secure();
							 | 
						|
								        List<int> seeds = [];
							 | 
						|
								        for (int i = 0; i < 32; i++) {
							 | 
						|
								            seeds.add(random.nextInt(255));
							 | 
						|
								        }
							 | 
						|
								        secureRandom.seed(KeyParameter(Uint8List.fromList(seeds)));
							 | 
						|
								
							 | 
						|
								        return secureRandom;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // Generate RSA key pair
							 | 
						|
								    AsymmetricKeyPair<RSAPublicKey, RSAPrivateKey> generateRSAkeyPair({int bitLength = 2048}) {
							 | 
						|
								        var secureRandom = this.secureRandom();
							 | 
						|
								
							 | 
						|
								        // final keyGen = KeyGenerator('RSA'); // Get using registry
							 | 
						|
								        final keyGen = RSAKeyGenerator();
							 | 
						|
								
							 | 
						|
								        keyGen.init(ParametersWithRandom(
							 | 
						|
								                        RSAKeyGeneratorParameters(BigInt.parse('65537'), bitLength, 64),
							 | 
						|
								                        secureRandom));
							 | 
						|
								
							 | 
						|
								        // Use the generator
							 | 
						|
								
							 | 
						|
								        final pair = keyGen.generateKeyPair();
							 | 
						|
								
							 | 
						|
								        // Cast the generated key pair into the RSA key types
							 | 
						|
								
							 | 
						|
								        final myPublic = pair.publicKey as RSAPublicKey;
							 | 
						|
								        final myPrivate = pair.privateKey as RSAPrivateKey;
							 | 
						|
								
							 | 
						|
								        return AsymmetricKeyPair<RSAPublicKey, RSAPrivateKey>(myPublic, myPrivate);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    // Encrypt data using RSA key
							 | 
						|
								    Uint8List rsaEncrypt(RSAPublicKey myPublic, Uint8List dataToEncrypt) {
							 | 
						|
								        final encryptor = OAEPEncoding(RSAEngine())
							 | 
						|
								                ..init(true, PublicKeyParameter<RSAPublicKey>(myPublic)); // true=encrypt
							 | 
						|
								
							 | 
						|
								        return _processInBlocks(encryptor, dataToEncrypt);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    // Decrypt data using RSA key
							 | 
						|
								    Uint8List rsaDecrypt(RSAPrivateKey myPrivate, Uint8List cipherText) {
							 | 
						|
								        final decryptor = OAEPEncoding(RSAEngine())
							 | 
						|
								                ..init(false, PrivateKeyParameter<RSAPrivateKey>(myPrivate)); // false=decrypt
							 | 
						|
								
							 | 
						|
								        return _processInBlocks(decryptor, cipherText);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    // Process blocks after encryption/descryption
							 | 
						|
								    Uint8List _processInBlocks(AsymmetricBlockCipher engine, Uint8List input) {
							 | 
						|
								        final numBlocks = input.length ~/ engine.inputBlockSize +
							 | 
						|
								                ((input.length % engine.inputBlockSize != 0) ? 1 : 0);
							 | 
						|
								
							 | 
						|
								        final output = Uint8List(numBlocks * engine.outputBlockSize);
							 | 
						|
								
							 | 
						|
								        var inputOffset = 0;
							 | 
						|
								        var outputOffset = 0;
							 | 
						|
								        while (inputOffset < input.length) {
							 | 
						|
								            final chunkSize = (inputOffset + engine.inputBlockSize <= input.length)
							 | 
						|
								                    ? engine.inputBlockSize
							 | 
						|
								                    : input.length - inputOffset;
							 | 
						|
								
							 | 
						|
								            outputOffset += engine.processBlock(
							 | 
						|
								                    input, inputOffset, chunkSize, output, outputOffset);
							 | 
						|
								
							 | 
						|
								            inputOffset += chunkSize;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return (output.length == outputOffset)
							 | 
						|
								                ? output
							 | 
						|
								                : output.sublist(0, outputOffset);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    // Encode RSA public key to pem format
							 | 
						|
								    static encodePublicKeyToPem(RSAPublicKey publicKey) {
							 | 
						|
								        var algorithmSeq = ASN1Sequence();
							 | 
						|
								        var algorithmAsn1Obj = ASN1Object.fromBytes(Uint8List.fromList([0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1, 0x1, 0x1]));
							 | 
						|
								        var paramsAsn1Obj = ASN1Object.fromBytes(Uint8List.fromList([0x5, 0x0]));
							 | 
						|
								        algorithmSeq.add(algorithmAsn1Obj);
							 | 
						|
								        algorithmSeq.add(paramsAsn1Obj);
							 | 
						|
								
							 | 
						|
								        var publicKeySeq = ASN1Sequence();
							 | 
						|
								        publicKeySeq.add(ASN1Integer(publicKey.modulus!));
							 | 
						|
								        publicKeySeq.add(ASN1Integer(publicKey.exponent!));
							 | 
						|
								        var publicKeySeqBitString = ASN1BitString(Uint8List.fromList(publicKeySeq.encodedBytes));
							 | 
						|
								
							 | 
						|
								        var topLevelSeq = 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-----""";
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // Parse public key PEM file
							 | 
						|
								    static parsePublicKeyFromPem(pemString) {
							 | 
						|
								        List<int> publicKeyDER = decodePEM(pemString);
							 | 
						|
								        var asn1Parser = ASN1Parser(Uint8List.fromList(publicKeyDER));
							 | 
						|
								        var topLevelSeq = asn1Parser.nextObject() as ASN1Sequence;
							 | 
						|
								        var publicKeyBitString = topLevelSeq.elements[1];
							 | 
						|
								
							 | 
						|
								        var publicKeyAsn = ASN1Parser(publicKeyBitString.contentBytes()!, relaxedParsing: true);
							 | 
						|
								        var publicKeySeq = publicKeyAsn.nextObject() as ASN1Sequence;
							 | 
						|
								        var modulus = publicKeySeq.elements[0] as ASN1Integer;
							 | 
						|
								        var exponent = publicKeySeq.elements[1] as ASN1Integer;
							 | 
						|
								
							 | 
						|
								        RSAPublicKey rsaPublicKey = RSAPublicKey(
							 | 
						|
								                modulus.valueAsBigInteger!,
							 | 
						|
								                exponent.valueAsBigInteger!
							 | 
						|
								        );
							 | 
						|
								
							 | 
						|
								        return rsaPublicKey;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    // Encode RSA private key to pem format
							 | 
						|
								    static encodePrivateKeyToPem(RSAPrivateKey privateKey) {
							 | 
						|
								        var version = ASN1Integer(BigInt.zero);
							 | 
						|
								
							 | 
						|
								        var algorithmSeq = ASN1Sequence();
							 | 
						|
								        var algorithmAsn1Obj = ASN1Object.fromBytes(Uint8List.fromList([
							 | 
						|
								            0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1, 0x1, 0x1
							 | 
						|
								        ]));
							 | 
						|
								        var paramsAsn1Obj = ASN1Object.fromBytes(Uint8List.fromList([0x5, 0x0]));
							 | 
						|
								        algorithmSeq.add(algorithmAsn1Obj);
							 | 
						|
								        algorithmSeq.add(paramsAsn1Obj);
							 | 
						|
								
							 | 
						|
								        var privateKeySeq = ASN1Sequence();
							 | 
						|
								        var modulus = ASN1Integer(privateKey.n!);
							 | 
						|
								        var publicExponent = ASN1Integer(BigInt.parse('65537'));
							 | 
						|
								        var privateExponent = ASN1Integer(privateKey.privateExponent!);
							 | 
						|
								        var p = ASN1Integer(privateKey.p!);
							 | 
						|
								        var q = ASN1Integer(privateKey.q!);
							 | 
						|
								        var dP = privateKey.privateExponent! % (privateKey.p! - BigInt.one);
							 | 
						|
								        var exp1 = ASN1Integer(dP);
							 | 
						|
								        var dQ = privateKey.privateExponent! % (privateKey.q! - BigInt.one);
							 | 
						|
								        var exp2 = ASN1Integer(dQ);
							 | 
						|
								        var iQ = privateKey.q?.modInverse(privateKey.p!);
							 | 
						|
								        var co = ASN1Integer(iQ!);
							 | 
						|
								
							 | 
						|
								        privateKeySeq.add(version);
							 | 
						|
								        privateKeySeq.add(modulus);
							 | 
						|
								        privateKeySeq.add(publicExponent);
							 | 
						|
								        privateKeySeq.add(privateExponent);
							 | 
						|
								        privateKeySeq.add(p);
							 | 
						|
								        privateKeySeq.add(q);
							 | 
						|
								        privateKeySeq.add(exp1);
							 | 
						|
								        privateKeySeq.add(exp2);
							 | 
						|
								        privateKeySeq.add(co);
							 | 
						|
								        var publicKeySeqOctetString = ASN1OctetString(Uint8List.fromList(privateKeySeq.encodedBytes));
							 | 
						|
								
							 | 
						|
								        var topLevelSeq = ASN1Sequence();
							 | 
						|
								        topLevelSeq.add(version);
							 | 
						|
								        topLevelSeq.add(algorithmSeq);
							 | 
						|
								        topLevelSeq.add(publicKeySeqOctetString);
							 | 
						|
								        var dataBase64 = base64.encode(topLevelSeq.encodedBytes);
							 | 
						|
								
							 | 
						|
								        return """-----BEGIN PRIVATE KEY-----\r\n$dataBase64\r\n-----END PRIVATE KEY-----""";
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    static parsePrivateKeyFromPem(pemString) {
							 | 
						|
								        List<int> privateKeyDER = decodePEM(pemString);
							 | 
						|
								        var asn1Parser = ASN1Parser(Uint8List.fromList(privateKeyDER));
							 | 
						|
								        var topLevelSeq = asn1Parser.nextObject() as ASN1Sequence;
							 | 
						|
								        var version = topLevelSeq.elements[0];
							 | 
						|
								        var algorithm = topLevelSeq.elements[1];
							 | 
						|
								        var privateKey = topLevelSeq.elements[2];
							 | 
						|
								
							 | 
						|
								        asn1Parser = ASN1Parser(privateKey.contentBytes()!);
							 | 
						|
								        var pkSeq = asn1Parser.nextObject() as ASN1Sequence;
							 | 
						|
								
							 | 
						|
								        version = pkSeq.elements[0];
							 | 
						|
								        var modulus = pkSeq.elements[1] as ASN1Integer;
							 | 
						|
								        //var publicExponent = pkSeq.elements[2] as ASN1Integer;
							 | 
						|
								        var privateExponent = pkSeq.elements[3] as ASN1Integer;
							 | 
						|
								        var p = pkSeq.elements[4] as ASN1Integer;
							 | 
						|
								        var q = pkSeq.elements[5] as ASN1Integer;
							 | 
						|
								        var exp1 = pkSeq.elements[6] as ASN1Integer;
							 | 
						|
								        var exp2 = pkSeq.elements[7] as ASN1Integer;
							 | 
						|
								        var co = pkSeq.elements[8] as ASN1Integer;
							 | 
						|
								
							 | 
						|
								        RSAPrivateKey rsaPrivateKey = RSAPrivateKey(
							 | 
						|
								                modulus.valueAsBigInteger!,
							 | 
						|
								                privateExponent.valueAsBigInteger!,
							 | 
						|
								                p.valueAsBigInteger,
							 | 
						|
								                q.valueAsBigInteger
							 | 
						|
								        );
							 | 
						|
								
							 | 
						|
								        return rsaPrivateKey;
							 | 
						|
								    }
							 | 
						|
								}
							 |