Ejemplo n.º 1
0
 /// <summary>Return the decrypted session data for the packet.</summary>
 private static byte[] GetSessionData(SymmetricKeyEncSessionPacket keyData, ReadOnlySpan <byte> rawPassword)
 {
     byte[] key = Array.Empty <byte>();
     try
     {
         key = new byte[PgpUtilities.GetKeySize(keyData.EncAlgorithm) / 8];
         S2kBasedEncryption.MakeKey(rawPassword, keyData.S2k.HashAlgorithm, keyData.S2k.GetIV(), keyData.S2k.IterationCount, key);
         if (keyData.SecKeyData?.Length > 0)
         {
             using var keyCipher    = PgpUtilities.GetSymmetricAlgorithm(keyData.EncAlgorithm);
             using var keyDecryptor = new ZeroPaddedCryptoTransform(keyCipher.CreateDecryptor(key, new byte[(keyCipher.BlockSize + 7) / 8]));
             return(keyDecryptor.TransformFinalBlock(keyData.SecKeyData, 0, keyData.SecKeyData.Length));
         }
         else
         {
             var sessionData = new byte[key.Length + 1];
             sessionData[0] = (byte)keyData.EncAlgorithm;
             key.CopyTo(sessionData, 1);
             return(sessionData);
         }
     }
     finally
     {
         CryptographicOperations.ZeroMemory(key);
     }
 }
 public override ContainedPacket GetSessionInfoPacket(byte[] sessionInfo)
 {
     using var symmetricAlgorithm = PgpUtilities.GetSymmetricAlgorithm(encAlgorithm);
     using var encryptor          = new ZeroPaddedCryptoTransform(symmetricAlgorithm.CreateEncryptor(key, new byte[(symmetricAlgorithm.BlockSize + 7) / 8]));
     return(new SymmetricKeyEncSessionPacket(encAlgorithm, s2k, encryptor.TransformFinalBlock(sessionInfo, 0, sessionInfo.Length - 2)));
 }
Ejemplo n.º 3
0
        public static void EncryptSecretKey(
            ReadOnlySpan <byte> password,
            S2kParameters s2kParameters,
            ReadOnlySpan <byte> source,
            Span <byte> destination,
            int version = 4)
        {
            if (password.Length == 0)
            {
                destination[0] = (byte)S2kUsageTag.None;
                source.CopyTo(destination.Slice(1));
                return;
            }

            using var c = PgpUtilities.GetSymmetricAlgorithm(s2kParameters.EncryptionAlgorithm);

            int         keySizeInBytes = (c.KeySize + 7) / 8;
            Span <byte> keyBytes       = stackalloc byte[keySizeInBytes];

            if (version <= 3)
            {
                MakeKey(password, PgpHashAlgorithm.MD5, Array.Empty <byte>(), 0, keyBytes);

                destination[0] = (byte)s2kParameters.EncryptionAlgorithm;

                c.GenerateIV();
                c.IV.CopyTo(destination.Slice(1));
                int bytesWritten = 13 + ((c.BlockSize + 7) / 8);
                destination = destination.Slice(bytesWritten);

                c.Key = keyBytes.ToArray();

                int checksum = 0;
                foreach (var b in source)
                {
                    checksum += b;
                }

                for (int i = 0; i < 4; i++)
                {
                    using var encryptor = new ZeroPaddedCryptoTransform(c.CreateEncryptor());

                    destination[0] = source[0];
                    destination[1] = source[1];

                    var mpInteger = MPInteger.ReadInteger(source, out int bytesConsumed).ToArray();
                    source = source.Slice(bytesConsumed);

                    var data = encryptor.TransformFinalBlock(mpInteger, 0, mpInteger.Length);
                    data.AsSpan().CopyTo(destination.Slice(2));
                    destination = destination.Slice(2 + data.Length);
                    CryptographicOperations.ZeroMemory(mpInteger);

                    if (i != 4)
                    {
                        c.IV = data.AsSpan(data.Length - (c.BlockSize / 8)).ToArray();
                    }
                }

                destination[0] = (byte)(checksum >> 8);
                destination[1] = (byte)(checksum);
            }
            else
            {
                var salt = new byte[8];
                RandomNumberGenerator.Fill(salt);
                byte rawIterationCount = 0x60;
                int  iterationCount    = (16 + (rawIterationCount & 15)) << ((rawIterationCount >> 4) + 6);

                MakeKey(password, s2kParameters.HashAlgorithm, salt, iterationCount, keyBytes);

                destination[0] = (byte)s2kParameters.UsageTag;
                destination[1] = (byte)s2kParameters.EncryptionAlgorithm;
                destination[2] = 3; // Salted & iterated
                destination[3] = (byte)s2kParameters.HashAlgorithm;

                salt.CopyTo(destination.Slice(4));
                destination[12] = rawIterationCount;

                c.GenerateIV();
                c.IV.CopyTo(destination.Slice(13));
                int bytesWritten = 13 + ((c.BlockSize + 7) / 8);
                destination = destination.Slice(bytesWritten);

                c.Key = keyBytes.ToArray();

                using var encryptor = new ZeroPaddedCryptoTransform(c.CreateEncryptor());
                byte[] checksumBytes;

                if (s2kParameters.UsageTag == S2kUsageTag.Sha1)
                {
                    using var sha1 = IncrementalHash.CreateHash(HashAlgorithmName.SHA1);
                    sha1.AppendData(source);
                    checksumBytes = sha1.GetHashAndReset();
                }
                else
                {
                    int checksum = 0;
                    foreach (var b in source)
                    {
                        checksum += b;
                    }
                    checksumBytes = new byte[] { (byte)(checksum >> 8), (byte)checksum };
                }

                var decSource = new byte[source.Length + checksumBytes.Length];
                source.CopyTo(decSource);
                checksumBytes.CopyTo(decSource, source.Length);

                var data = encryptor.TransformFinalBlock(decSource, 0, decSource.Length);
                data.AsSpan().CopyTo(destination);

                CryptographicOperations.ZeroMemory(data);
                CryptographicOperations.ZeroMemory(decSource);
            }
        }
Ejemplo n.º 4
0
        public static void DecryptSecretKey(ReadOnlySpan <byte> password, ReadOnlySpan <byte> source, Span <byte> destination, out int bytesWritten, int version = 4)
        {
            S2kUsageTag usageTag = (S2kUsageTag)source[0];
            PgpSymmetricKeyAlgorithm encryptionAlgorithm;
            var              salt           = new ReadOnlySpan <byte>();
            long             iterationCount = 0;
            PgpHashAlgorithm hashAlgorithm;

            if (usageTag == S2kUsageTag.Checksum || usageTag == S2kUsageTag.Sha1 /* || usageTag == S2kUsageTag.Aead */)
            {
                encryptionAlgorithm = (PgpSymmetricKeyAlgorithm)source[1];
                byte s2kType = source[2];
                hashAlgorithm = (PgpHashAlgorithm)source[3];
                source        = source.Slice(4);
                if (s2kType > 0 && s2kType <= 3)
                {
                    salt   = source.Slice(0, 8);
                    source = source.Slice(8);
                    if (s2kType == 3)
                    {
                        iterationCount = (16 + (source[0] & 15)) << ((source[0] >> 4) + 6);
                        source         = source.Slice(1);
                    }
                }
                else if (s2kType == 101) // GNU private
                {
                    throw new NotImplementedException();
                }
                else
                {
                    throw new CryptographicException(); // Unknown S2K type
                }
            }
            else if (usageTag == S2kUsageTag.None)
            {
                // No encryption
                bytesWritten = source.Slice(1).TryCopyTo(destination) ? source.Length : 0;
                return;
            }
            else
            {
                // No salt, no iterations, MD5 hash
                encryptionAlgorithm = (PgpSymmetricKeyAlgorithm)usageTag;
                hashAlgorithm       = PgpHashAlgorithm.MD5;
                usageTag            = S2kUsageTag.Checksum;
                source = source.Slice(1);
            }

            int         keySizeInBytes = (PgpUtilities.GetKeySize(encryptionAlgorithm) + 7) / 8;
            Span <byte> keyBytes       = stackalloc byte[keySizeInBytes];

            try
            {
                MakeKey(password, hashAlgorithm, salt, iterationCount, keyBytes);

                using var c = PgpUtilities.GetSymmetricAlgorithm(encryptionAlgorithm);

                // Read the IV
                c.IV  = source.Slice(0, c.BlockSize / 8).ToArray();
                c.Key = keyBytes.ToArray();

                source = source.Slice(c.BlockSize / 8);

                if (destination.Length < source.Length)
                {
                    bytesWritten = 0;
                    return;
                }

                // Do the actual decryption
                bytesWritten = source.Length;
                if (version == 4)
                {
                    using var decryptor = new ZeroPaddedCryptoTransform(c.CreateDecryptor());
                    var data = decryptor.TransformFinalBlock(source.ToArray(), 0, source.Length);
                    data.AsSpan().CopyTo(destination);
                    CryptographicOperations.ZeroMemory(data);
                }
                else if (version == 3)
                {
                    // Version 3 is four RSA parameters encoded as MPIntegers separately
                    var sourceArray = source.ToArray();
                    int pos         = 0;
                    for (int i = 0; i != 4; i++)
                    {
                        int encLen = ((source[pos] << 8) + source[pos + 1] + 7) / 8;
                        destination[pos]     = source[pos];
                        destination[pos + 1] = source[pos + 1];
                        pos += 2;

                        if (encLen > source.Length - pos)
                        {
                            throw new PgpException("out of range encLen found in encData");
                        }

                        using var decryptor = new ZeroPaddedCryptoTransform(c.CreateDecryptor());
                        var data = decryptor.TransformFinalBlock(sourceArray, pos, encLen);
                        data.CopyTo(destination.Slice(pos));
                        CryptographicOperations.ZeroMemory(data);
                        pos += encLen;

                        if (i != 3)
                        {
                            c.IV = source.Slice(pos - (c.BlockSize / 8), c.BlockSize / 8).ToArray();
                        }
                    }

                    destination[pos]     = source[pos];
                    destination[pos + 1] = source[pos + 1];
                }

                if (!VerifyChecksum(usageTag, destination.Slice(0, bytesWritten), out int checksumLength))
                {
                    throw new CryptographicException();
                }

                bytesWritten -= checksumLength;
            }
            finally
            {
                CryptographicOperations.ZeroMemory(keyBytes);
            }
        }
Ejemplo n.º 5
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());
        }