-
-
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-----"""; | |
} | |
} |
Hi, thanks for the work, it saved me a lot of time, I have a few additions.
RsaKeyHelper().parsePublicKeyFromPem(certFile.trim()); An error was reported using this method.
Unhandled exception: type 'ASN1ObjectIdentifier' is not a subtype of type 'ASN1Sequence' #0 RsaKeyHelper.parsePublicKeyFromPem (package:flutter_app/utils/rsa_pem.dart:106:18) #1 main (package:flutter_app/utils/encryptUtils.dart:80:43) #2 _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:289:19) #3 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
Here's my pem:
-----BEGIN CERTIFICATE----- MIIDQzCCAiugAwIBAgIEM6flhTANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJ6 aDELMAkGA1UECBMCaHoxCzAJBgNVBAcTAmh6MQ0wCwYDVQQKEwRkZHNjMQ0wCwYD VQQLEwRkZHNjMQswCQYDVQQDEwJsaTAeFw0xNzA0MjAwNzI4NDVaFw0xNzA3MTkw NzI4NDVaMFIxCzAJBgNVBAYTAnpoMQswCQYDVQQIEwJoejELMAkGA1UEBxMCaHox DTALBgNVBAoTBGRkc2MxDTALBgNVBAsTBGRkc2MxCzAJBgNVBAMTAmxpMIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmG0F8Q5hg67kRSm1etU1m8ruWb9E kal1bsVUAdWNPc+391ycRYqFt3WfW59vOX4aUC2q1yygJCq+LlMZKCV7FgiqAhMT 56PFcCLp9E8HXjx1xfp38T/gItSWX5JWBY8bKjSgAHj81/F4lopPJs1b/p7tph3n KFSHcWOyi0svQa7hPMpLZtYuwAGwNnB54+TorXMcNgJoAmy3VULTP5orJq2r3drK JJdFakRM0IYlBn09gpE3szQKMlCF9/Ao23LXVG43kNDWvyU1vJe9ObYWrB6JCe2K 6kSVobr0vsTyPn/xtKGaEQfv4mC0aPf1eVJp3o1WIbu+PLYyZiBMZqfHhQIDAQAB oyEwHzAdBgNVHQ4EFgQUawZr7dWmL7f2gIz20Pcl/0TKdp4wDQYJKoZIhvcNAQEL BQADggEBAExNe354GXt03oTNix9o7GG0Xx7ozK3hTjm6aW895JIPiSxh5Fj1arqu xidjOW4v0QT2oyhdsxNMr65Q6aXSBr+u3O30iPZRWRBIcWezUhq46067Wo+HYx1u mE5kiEkZ+pjTxWEZtOncOTuhlnsCEAQ28Jb24mwCeTB5eSBM9oKX5crTMXvJO73U /T4D5bg63goiNP61LUF5d3T5kK+0SkxYk+L8e6U1LTaJCEFD0jJEU5JM4nG1N4zX iB88NijY7YlM/F03Ph3GXx52SWTIToI0h6bSbbhKM00974z63w0sFm4WpZcOE0Px 3ugLoSKVaZKa99NCbgQiRNpGsy7ixTo= -----END CERTIFICATE-----
I finished it in Java now,
If you have time, you can try to solve it
thank you
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
Hi, thanks for the work, it saved me a lot of time, I have a few additions.
Worth adding in _decodePem
"----- BEGIN RSA PRIVATE KEY -----"
and "----- END RSA PRIVATE KEY -----"
With these headers, keys are mainly generated, for example, on android, ios packages from the box for generation add these headers. For public keys, it’s also worth adding
----- BEGIN RSA PUBLIC KEY -----
----- END RSA PUBLIC KEY -----
because the native iOS key generator generates a public key with these headers
In accordance with this standard when converting to pem format, the line should be divided by 64 characters each, in some libraries this causes the ability to not read the key.
Solution to the forehead