/// <summary> /// Parse a secret key from one of the GPG S expression keys. /// </summary> internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, PgpKey?pubKey) { SXprReader reader = new SXprReader(inputStream); reader.SkipOpenParenthesis(); string type = reader.ReadString(); if (type.Equals("protected-private-key", StringComparison.Ordinal)) { reader.SkipOpenParenthesis(); string curveName; Oid curveOid; string keyType = reader.ReadString(); if (keyType.Equals("ecc", StringComparison.Ordinal)) { reader.SkipOpenParenthesis(); string curveID = reader.ReadString(); curveName = reader.ReadString(); switch (curveName) { case "NIST P-256": curveOid = new Oid("1.2.840.10045.3.1.7"); break; case "NIST P-384": curveOid = new Oid("1.3.132.0.34"); break; case "NIST P-521": curveOid = new Oid("1.3.132.0.35"); break; case "brainpoolP256r1": curveOid = new Oid("1.3.36.3.3.2.8.1.1.7"); break; case "brainpoolP384r1": curveOid = new Oid("1.3.36.3.3.2.8.1.1.11"); break; case "brainpoolP512r1": curveOid = new Oid("1.3.36.3.3.2.8.1.1.13"); break; case "Curve25519": curveOid = new Oid("1.3.6.1.4.1.3029.1.5.1"); break; case "Ed25519": curveOid = new Oid("1.3.6.1.4.1.11591.15.1"); break; default: throw new PgpException("unknown curve algorithm"); } reader.SkipCloseParenthesis(); } else { throw new PgpException("no curve details found"); } byte[] qVal; string?flags = null; reader.SkipOpenParenthesis(); type = reader.ReadString(); if (type == "flags") { // Skip over flags flags = reader.ReadString(); reader.SkipCloseParenthesis(); reader.SkipOpenParenthesis(); type = reader.ReadString(); } if (type.Equals("q", StringComparison.Ordinal)) { qVal = reader.ReadBytes(); } else { throw new PgpException("no q value found"); } if (pubKey == null) { var writer = new AsnWriter(AsnEncodingRules.DER); writer.WriteObjectIdentifier(curveOid.Value !); int expectedLength = writer.GetEncodedLength() + 2 + qVal.Length; var destination = new byte[expectedLength]; writer.TryEncode(destination, out int oidBytesWritten); Keys.MPInteger.TryWriteInteger(qVal, destination.AsSpan(oidBytesWritten), out int qBytesWritten); var pubKeyBytes = destination.AsSpan(1, oidBytesWritten + qBytesWritten - 1).ToArray(); PublicKeyPacket pubPacket = new PublicKeyPacket( flags == "eddsa" ? PgpPublicKeyAlgorithm.EdDsa : PgpPublicKeyAlgorithm.ECDsa, DateTime.UtcNow, pubKeyBytes); pubKey = new PgpPublicKey(pubPacket); } reader.SkipCloseParenthesis(); byte[] dValue = GetDValue(reader, pubKey.KeyPacket, rawPassPhrase, curveName); var keyBytes = new byte[pubKey.KeyPacket.PublicKeyLength + 3 + dValue.Length]; pubKey.KeyPacket.KeyBytes.AsSpan(0, pubKey.KeyPacket.PublicKeyLength).CopyTo(keyBytes); keyBytes[pubKey.KeyPacket.PublicKeyLength] = (byte)S2kUsageTag.None; Keys.MPInteger.TryWriteInteger(dValue, keyBytes.AsSpan(pubKey.KeyPacket.PublicKeyLength + 1), out var _); return(new PgpSecretKey(new SecretKeyPacket(pubKey.Algorithm, pubKey.CreationTime, keyBytes), pubKey)); } throw new PgpException("unknown key type found"); }