예제 #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)));
 }
        /// <summary>
        /// Return an output stream which will encrypt the data as it is written to it.
        /// </summary>
        protected override IPacketWriter Open()
        {
            var writer = base.Open();

            if (cOut != null)
            {
                throw new InvalidOperationException("generator already in open state");
            }
            // TODO: Do we want compatibility with old PGP? (IDEA + no password iirc)
            if (methods.Count == 0)
            {
                throw new InvalidOperationException("No encryption methods specified");
            }

            var c = PgpUtilities.GetSymmetricAlgorithm(defAlgorithm);

            if (methods.Count == 1 && methods[0] is PbeMethod)
            {
                PbeMethod m = (PbeMethod)methods[0];
                c.Key = m.GetKey();
                writer.WritePacket(m.GetSessionInfoPacket());
            }
            else
            {
                c.GenerateKey();
                byte[] sessionInfo = CreateSessionInfo(defAlgorithm, c.Key);

                foreach (EncMethod m in methods)
                {
                    writer.WritePacket(m.GetSessionInfoPacket(sessionInfo));
                }
            }

            try
            {
                if (withIntegrityPacket)
                {
                    pOut = writer.GetPacketStream(new SymmetricEncIntegrityPacket());
                }
                else
                {
                    pOut = writer.GetPacketStream(new SymmetricEncDataPacket());
                }

                int    blockSize = (c.BlockSize + 7) / 8;
                byte[] inLineIv  = new byte[blockSize * 2]; // Aligned to block size
                RandomNumberGenerator.Fill(inLineIv.AsSpan(0, blockSize));
                inLineIv[blockSize]     = inLineIv[blockSize - 2];
                inLineIv[blockSize + 1] = inLineIv[blockSize - 1];

                ICryptoTransform encryptor;
                c.IV = new byte[blockSize];
                if (withIntegrityPacket)
                {
                    encryptor = c.CreateEncryptor();
                }
                else
                {
                    encryptor = c.CreateEncryptor();
                    var encryptedInlineIv = encryptor.TransformFinalBlock(inLineIv, 0, inLineIv.Length);
                    pOut.Write(encryptedInlineIv.AsSpan(0, blockSize + 2));
                    c.IV      = encryptedInlineIv.AsSpan(2, blockSize).ToArray();
                    encryptor = c.CreateEncryptor();
                }

                Stream myOut = cOut = new CryptoStream(pOut, new ZeroPaddedCryptoTransform(encryptor), CryptoStreamMode.Write);

                if (withIntegrityPacket)
                {
                    digest = SHA1.Create();
                    myOut  = digestOut = new CryptoStream(new FilterStream(myOut), digest, CryptoStreamMode.Write);
                    myOut.Write(inLineIv, 0, blockSize + 2);
                }

                return(writer.CreateNestedWriter(new WrappedGeneratorStream(myOut, _ => Close())));
            }
            catch (Exception e)
            {
                throw new PgpException("Exception creating cipher", e);
            }
        }
예제 #4
0
        private Stream GetDataStream(ReadOnlySpan <byte> sessionData, bool verifyIntegrity)
        {
            PgpSymmetricKeyAlgorithm keyAlgorithm = (PgpSymmetricKeyAlgorithm)sessionData[0];

            if (keyAlgorithm == PgpSymmetricKeyAlgorithm.Null)
            {
                return(inputStream);
            }

            var key = sessionData.Slice(1);
            SymmetricAlgorithm encryptionAlgorithm = PgpUtilities.GetSymmetricAlgorithm(keyAlgorithm);
            var iv = new byte[(encryptionAlgorithm.BlockSize + 7) / 8];

            byte[]           keyArray = Array.Empty <byte>();
            ICryptoTransform decryptor;
            var inlineIv = new byte[iv.Length * 2]; // Aligned to block size

            try
            {
                keyArray  = key.ToArray();
                decryptor = encryptionAlgorithm.CreateDecryptor(keyArray, iv);
                if (encryptedPacket is SymmetricEncDataPacket)
                {
                    if (inputStream.ReadFully(inlineIv.AsSpan(0, iv.Length + 2)) < iv.Length + 2)
                    {
                        throw new EndOfStreamException();
                    }

                    var decryptedInlineIv = decryptor.TransformFinalBlock(inlineIv, 0, inlineIv.Length);
                    if (verifyIntegrity)
                    {
                        VerifyInlineIV(decryptedInlineIv.AsSpan(0, iv.Length), decryptedInlineIv.AsSpan(iv.Length, 2));
                    }

                    // Perform reset according to the OpenPGP CFB rules
                    decryptor = encryptionAlgorithm.CreateDecryptor(keyArray, inlineIv.AsSpan(2, iv.Length).ToArray());
                }
            }
            finally
            {
                CryptographicOperations.ZeroMemory(keyArray.AsSpan());
            }

            encStream = new CryptoStream(
                inputStream,
                new ZeroPaddedCryptoTransform(decryptor),
                CryptoStreamMode.Read);
            if (encryptedPacket is SymmetricEncIntegrityPacket)
            {
                hashAlgorithm          = SHA1.Create();
                tailEndCryptoTransform = new TailEndCryptoTransform(hashAlgorithm, hashAlgorithm.HashSize / 8);
                encStream = new CryptoStream(encStream, tailEndCryptoTransform, CryptoStreamMode.Read);

                if (encStream.ReadFully(inlineIv.AsSpan(0, iv.Length + 2)) < iv.Length + 2)
                {
                    throw new EndOfStreamException();
                }

                if (verifyIntegrity)
                {
                    VerifyInlineIV(inlineIv.AsSpan(0, iv.Length), inlineIv.AsSpan(iv.Length, 2));
                }
            }

            return(encStream);
        }
예제 #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());
        }