Exemplo n.º 1
0
        /// <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");
        }