loadPrivateKeyFromPKCS8Ed25519 static method
Reads a not encrypted PKCS#8 file and returns a 32-Byte-Ed25519-Seed.
PKCS#8 structure (RFC8410) with OID 1.3.101.112 (Ed25519):
PrivateKeyInfo ::= SEQUENCE { version INTEGER (0), privateKeyAlgorithm SEQUENCE { algorithm OBJECT IDENTIFIER (1.3.101.112), parameters (ABSENT oder NULL) }, privateKey OCTET STRING -- the seed }
Implementation
static Uint8List loadPrivateKeyFromPKCS8Ed25519(String pem) {
const header = '-----BEGIN PRIVATE KEY-----';
const footer = '-----END PRIVATE KEY-----';
if (!pem.contains(header) || !pem.contains(footer)) {
throw ArgumentError(
'Not a valid PKCS#8 PEM (BEGIN/END PRIVATE KEY missing).',
);
}
final body = pem
.replaceAll(header, '')
.replaceAll(footer, '')
.replaceAll(RegExp(r'\s'), '');
final derBytes = base64.decode(body);
final asn1Parser = ASN1Parser(derBytes);
final topLevelSeq = asn1Parser.nextObject() as ASN1Sequence;
if (topLevelSeq.elements == null || topLevelSeq.elements!.length < 3) {
throw StateError('Unexpected structure in PKCS#8, to few fields');
}
final version = topLevelSeq.elements![0] as ASN1Integer;
if (version.integer?.toInt() != 0) {
throw StateError('Unexpected structure in PKCS#8, to few fields');
}
final algorithmSeq = topLevelSeq.elements![1] as ASN1Sequence;
if (algorithmSeq.elements == null || algorithmSeq.elements!.isEmpty) {
throw StateError('No algorithm identifier found');
}
final objectIdentifier = (algorithmSeq.elements![0] as ASN1ObjectIdentifier)
.objectIdentifierAsString;
if ("1.3.101.112" != objectIdentifier) {
throw ArgumentError(
'The key is not a Ed25519-Key (OID=$objectIdentifier)!',
);
}
final privateKeyOctetStr = topLevelSeq.elements![2] as ASN1OctetString;
final privateKeyBytes = privateKeyOctetStr.valueBytes;
Uint8List? ed25519Seed;
final innerParser = ASN1Parser(privateKeyBytes);
final possibleInner = innerParser.nextObject();
if (possibleInner is ASN1OctetString) {
final inner = possibleInner.valueBytes;
if (inner?.length == 32) {
ed25519Seed = inner;
}
}
if (ed25519Seed == null) {
if (privateKeyBytes?.length == 32) {
ed25519Seed = privateKeyBytes;
} else if (privateKeyBytes?.length == 64) {
ed25519Seed = privateKeyBytes?.sublist(0, 32);
} else {
throw StateError(
'PrivateKey has no valid length (32 or 64); found length: ${privateKeyBytes?.length}',
);
}
}
return ed25519Seed ?? Uint8List(0);
}