|
|
- 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;
- }
- }
|