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