-
-
Save proteye/982d9991922276ccfb011dfc55443d74 to your computer and use it in GitHub Desktop.
| import 'dart:convert'; | |
| import 'dart:math'; | |
| import 'dart:typed_data'; | |
| import "package:pointycastle/export.dart"; | |
| import "package:asn1lib/asn1lib.dart"; | |
| List<int> decodePEM(String pem) { | |
| var startsWith = [ | |
| "-----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.indexOf('BEGIN PGP') != -1; | |
| 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 { | |
| AsymmetricKeyPair<RSAPublicKey, RSAPrivateKey> generateKeyPair() { | |
| var keyParams = new RSAKeyGeneratorParameters(BigInt.parse('65537'), 2048, 12); | |
| var secureRandom = new FortunaRandom(); | |
| var random = new Random.secure(); | |
| List<int> 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(); | |
| } | |
| String encrypt(String plaintext, RSAPublicKey publicKey) { | |
| var cipher = new RSAEngine() | |
| ..init(true, new PublicKeyParameter<RSAPublicKey>(publicKey)); | |
| var cipherText = cipher.process(new Uint8List.fromList(plaintext.codeUnits)); | |
| return new String.fromCharCodes(cipherText); | |
| } | |
| String decrypt(String ciphertext, RSAPrivateKey privateKey) { | |
| var cipher = new RSAEngine() | |
| ..init(false, new PrivateKeyParameter<RSAPrivateKey>(privateKey)); | |
| var decrypted = cipher.process(new Uint8List.fromList(ciphertext.codeUnits)); | |
| return new String.fromCharCodes(decrypted); | |
| } | |
| parsePublicKeyFromPem(pemString) { | |
| List<int> publicKeyDER = decodePEM(pemString); | |
| var asn1Parser = new ASN1Parser(publicKeyDER); | |
| var topLevelSeq = asn1Parser.nextObject() as ASN1Sequence; | |
| var publicKeyBitString = topLevelSeq.elements[1]; | |
| var publicKeyAsn = new ASN1Parser(publicKeyBitString.contentBytes()); | |
| ASN1Sequence publicKeySeq = publicKeyAsn.nextObject(); | |
| var modulus = publicKeySeq.elements[0] as ASN1Integer; | |
| var exponent = publicKeySeq.elements[1] as ASN1Integer; | |
| RSAPublicKey rsaPublicKey = RSAPublicKey( | |
| modulus.valueAsBigInteger, | |
| exponent.valueAsBigInteger | |
| ); | |
| return rsaPublicKey; | |
| } | |
| parsePrivateKeyFromPem(pemString) { | |
| List<int> privateKeyDER = decodePEM(pemString); | |
| var asn1Parser = new ASN1Parser(privateKeyDER); | |
| var topLevelSeq = asn1Parser.nextObject() as ASN1Sequence; | |
| var version = topLevelSeq.elements[0]; | |
| var algorithm = topLevelSeq.elements[1]; | |
| var privateKey = topLevelSeq.elements[2]; | |
| asn1Parser = new 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; | |
| } | |
| 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 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-----"""; | |
| } | |
| encodePrivateKeyToPem(RSAPrivateKey privateKey) { | |
| var version = ASN1Integer(BigInt.from(0)); | |
| 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 privateKeySeq = new ASN1Sequence(); | |
| var modulus = ASN1Integer(privateKey.n); | |
| var publicExponent = ASN1Integer(BigInt.parse('65537')); | |
| var privateExponent = ASN1Integer(privateKey.d); | |
| var p = ASN1Integer(privateKey.p); | |
| var q = ASN1Integer(privateKey.q); | |
| var dP = privateKey.d % (privateKey.p - BigInt.from(1)); | |
| var exp1 = ASN1Integer(dP); | |
| var dQ = privateKey.d % (privateKey.q - BigInt.from(1)); | |
| 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 = new ASN1OctetString(Uint8List.fromList(privateKeySeq.encodedBytes)); | |
| var topLevelSeq = new 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-----"""; | |
| } | |
| } |
Hello and thank you for this work ,
but , there is an issue on method "parsePublicKeyFromPem() "
Unhandled exception: type 'ASN1ObjectIdentifier' is not a subtype of type 'ASN1Sequence' #0 RsaKeyHelper.parsePublicKeyFromPem
BR
Hello and thank you for this work ,
but , there is an issue on method "parsePublicKeyFromPem() "
Unhandled exception: type 'ASN1ObjectIdentifier' is not a subtype of type 'ASN1Sequence' #0 RsaKeyHelper.parsePublicKeyFromPem
BR
has anyone found fix for this ?
parsePrivateKeyFromPem function is helpful , thanks
Hello
To perform the parsePublicKeyFromPem() method, the parse ECPublicKey, result reported the following error.
Unhandled exception:
RangeError: Value not in range: 2329388466087989709
#0 _rangeCheck (dart:typed_data-patch/typed_data_patch.dart:4631:5)
#1 _ByteBuffer.asUint8List (dart:typed_data-patch/typed_data_patch.dart:1931:5)
#2 new Uint8List.view (dart:typed_data:847:19)
#3 ASN1Parser.nextObject
package:asn1lib/asn1parser.dart:45
#4 parsePublicKeyFromPem
test\signers\test.dart:63
#5 main
test\signers\test.dart:21
#6 _startIsolate. (dart:isolate-patch/isolate_patch.dart:307:19)
#7 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)
this code doesn't work anymore with the newer versions of the pointycastle library.
New Import:
import 'package:pointycastle/asymmetric/api.dart' as pointy;
Modified generateKeyPair():
AsymmetricKeyPair<pointy.RSAPublicKey, pointy.RSAPrivateKey> generateKeyPair() {
var keyParams =
new RSAKeyGeneratorParameters(BigInt.parse('65537'), 2048, 12);
var secureRandom = new FortunaRandom();
var random = new Random.secure();
List<int> 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);
AsymmetricKeyPair keyPair = k.generateKeyPair();
AsymmetricKeyPair<pointy.RSAPublicKey, pointy.RSAPrivateKey> pair =
AsymmetricKeyPair(keyPair.publicKey as pointy.RSAPublicKey,
keyPair.privateKey as pointy.RSAPrivateKey);
return pair;
}
Since this no longer works, I recommend using
https://raw.githubusercontent.com/Ephenodrom/Dart-Basic-Utils/master/lib/src/StringUtils.dart
and https://raw.githubusercontent.com/Ephenodrom/Dart-Basic-Utils/master/lib/src/CryptoUtils.dart
very very thanks!
Since this no longer works, I recommend using https://raw.githubusercontent.com/Ephenodrom/Dart-Basic-Utils/master/lib/src/StringUtils.dart and https://raw.githubusercontent.com/Ephenodrom/Dart-Basic-Utils/master/lib/src/CryptoUtils.dart
thks a lot!
That code is published on pub as the basic_utils in the CryptoUtils class:
https://pub.dev/packages/basic_utils#cryptoutils ✨
Adding the pub dep is the way to go vs copying in code (just update the package to get bugfixes / keep up with api changes etc).
Thanks men you saved me a lot of trouble
I finished it in Java now,
If you have time, you can try to solve it
thank you