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); }
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()); }