Esempio 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");
        }
Esempio n. 2
0
        private static byte[] GetDValue(SXprReader reader, KeyPacket publicKey, byte[] rawPassPhrase, string curveName)
        {
            string type;

            reader.SkipOpenParenthesis();

            string protection;
            string?protectedAt = null;
            S2k    s2k;

            byte[] iv;
            byte[] secKeyData;

            type = reader.ReadString();
            if (type.Equals("protected", StringComparison.Ordinal))
            {
                protection = reader.ReadString();

                reader.SkipOpenParenthesis();

                s2k = reader.ParseS2k();

                iv = reader.ReadBytes();

                reader.SkipCloseParenthesis();

                secKeyData = reader.ReadBytes();

                reader.SkipCloseParenthesis();

                reader.SkipOpenParenthesis();

                if (reader.ReadString().Equals("protected-at", StringComparison.Ordinal))
                {
                    protectedAt = reader.ReadString();
                }
            }
            else
            {
                throw new PgpException("protected block not found");
            }

            byte[] data;

            switch (protection)
            {
            case "openpgp-s2k3-sha1-aes256-cbc":
            case "openpgp-s2k3-sha1-aes-cbc":
                PgpSymmetricKeyAlgorithm symmAlg =
                    protection.Equals("openpgp-s2k3-sha1-aes256-cbc", StringComparison.Ordinal) ?
                    PgpSymmetricKeyAlgorithm.Aes256 :
                    PgpSymmetricKeyAlgorithm.Aes128;
                using (var c = PgpUtilities.GetSymmetricAlgorithm(symmAlg))
                {
                    var keyBytes = new byte[c.KeySize / 8];
                    S2kBasedEncryption.MakeKey(rawPassPhrase, PgpHashAlgorithm.Sha1, s2k.GetIV(), s2k.IterationCount, keyBytes);
                    c.Key  = keyBytes;
                    c.IV   = iv;
                    c.Mode = CipherMode.CBC;
                    using var decryptor = new ZeroPaddedCryptoTransform(c.CreateDecryptor());
                    data = decryptor.TransformFinalBlock(secKeyData, 0, secKeyData.Length);
                    // TODO: check SHA-1 hash.
                }
                break;

            case "openpgp-s2k3-ocb-aes":
            {
                MemoryStream aad = new MemoryStream();
                WriteSExprPublicKey(new SXprWriter(aad), publicKey, curveName, protectedAt);
                var keyBytes = new byte[16];
                S2kBasedEncryption.MakeKey(rawPassPhrase, PgpHashAlgorithm.Sha1, s2k.GetIV(), s2k.IterationCount, keyBytes);
                using var aesOcb = new AesOcb(keyBytes);
                data             = new byte[secKeyData.Length - 16];
                aesOcb.Decrypt(iv, secKeyData.AsSpan(0, secKeyData.Length - 16), secKeyData.AsSpan(secKeyData.Length - 16), data, aad.ToArray());
            }
            break;

            case "openpgp-native":
            default:
                throw new PgpException(protection + " key format is not supported yet");
            }

            //
            // parse the secret key S-expr
            //
            Stream keyIn = new MemoryStream(data, false);

            reader = new SXprReader(keyIn);
            reader.SkipOpenParenthesis();
            reader.SkipOpenParenthesis();
            reader.SkipOpenParenthesis();
            String name = reader.ReadString();

            return(reader.ReadBytes());
        }