/// <summary>Return the raw input stream for the data stream.</summary> public override Stream GetInputStream() { return(EncData.GetInputStream()); }
/// <summary>Return the decrypted input stream, using the passed in passphrase.</summary> public Stream GetDataStream(char[] passPhrase) { try { var keyAlgorithm = _keyData.EncAlgorithm; var key = PgpUtilities.MakeKeyFromPassPhrase( keyAlgorithm, _keyData.S2K, passPhrase); var secKeyData = _keyData.GetSecKeyData(); if (secKeyData != null && secKeyData.Length > 0) { var keyCipher = CipherUtilities.GetCipher( PgpUtilities.GetSymmetricCipherName(keyAlgorithm) + "/CFB/NoPadding"); keyCipher.Init(false, new ParametersWithIV(key, new byte[keyCipher.GetBlockSize()])); var keyBytes = keyCipher.DoFinal(secKeyData); keyAlgorithm = (SymmetricKeyAlgorithmTag)keyBytes[0]; key = ParameterUtilities.CreateKeyParameter( PgpUtilities.GetSymmetricCipherName(keyAlgorithm), keyBytes, 1, keyBytes.Length - 1); } var c = CreateStreamCipher(keyAlgorithm); var iv = new byte[c.GetBlockSize()]; c.Init(false, new ParametersWithIV(key, iv)); EncStream = BcpgInputStream.Wrap(new CipherStream(EncData.GetInputStream(), c, null)); if (EncData is SymmetricEncIntegrityPacket) { TruncStream = new TruncatedStream(EncStream); var digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1); var digest = DigestUtilities.GetDigest(digestName); EncStream = new DigestStream(TruncStream, digest, null); } if (Streams.ReadFully(EncStream, iv, 0, iv.Length) < iv.Length) { throw new EndOfStreamException("unexpected end of stream."); } var v1 = EncStream.ReadByte(); var v2 = EncStream.ReadByte(); if (v1 < 0 || v2 < 0) { throw new EndOfStreamException("unexpected end of stream."); } // Note: the oracle attack on the "quick check" bytes is not deemed // a security risk for PBE (see PgpPublicKeyEncryptedData) var repeatCheckPassed = iv[iv.Length - 2] == (byte)v1 && iv[iv.Length - 1] == (byte)v2; // Note: some versions of PGP appear to produce 0 for the extra // bytes rather than repeating the two previous bytes var zeroesCheckPassed = v1 == 0 && v2 == 0; if (!repeatCheckPassed && !zeroesCheckPassed) { throw new PgpDataValidationException("quick check failed."); } return(EncStream); } catch (PgpException) { throw; } catch (Exception e) { throw new PgpException("Exception creating cipher", e); } }
/// <summary> /// Gets the data stream. /// </summary> /// <param name="privKey">The priv key.</param> /// <param name="encryptionAlgorithm">The encryption algorithm.</param> /// <returns></returns> /// <exception cref="Org.BouncyCastle.Bcpg.OpenPgp.PgpException"> /// exception creating cipher /// or /// Exception starting decryption /// </exception> /// <exception cref="System.IO.EndOfStreamException"> /// unexpected end of stream. /// or /// unexpected end of stream. /// </exception> public Stream GetDataStream(IPgpPrivateKey privKey, out SymmetricKeyAlgorithmTag encryptionAlgorithm) { var plain = this.FetchSymmetricKeyData(privKey); encryptionAlgorithm = (SymmetricKeyAlgorithmTag)plain[0]; IBufferedCipher c2; var cipherName = PgpUtilities.GetSymmetricCipherName(encryptionAlgorithm); var cName = cipherName; try { if (EncData is SymmetricEncIntegrityPacket) { cName += "/CFB/NoPadding"; } else { cName += "/OpenPGPCFB/NoPadding"; } c2 = CipherUtilities.GetCipher(cName); } catch (PgpException) { throw; } catch (Exception e) { throw new PgpException("exception creating cipher", e); } if (c2 == null) { return(EncData.GetInputStream()); } try { var key = ParameterUtilities.CreateKeyParameter(cipherName, plain, 1, plain.Length - 3); var iv = new byte[c2.GetBlockSize()]; c2.Init(false, new ParametersWithIV(key, iv)); this.EncStream = BcpgInputStream.Wrap(new CipherStream(EncData.GetInputStream(), c2, null)); if (this.EncData is SymmetricEncIntegrityPacket) { this.TruncStream = new TruncatedStream(this.EncStream); var digest = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1)); EncStream = new DigestStream(TruncStream, digest, null); } if (Streams.ReadFully(EncStream, iv, 0, iv.Length) < iv.Length) { throw new EndOfStreamException("unexpected end of stream."); } var v1 = this.EncStream.ReadByte(); var v2 = this.EncStream.ReadByte(); if (v1 < 0 || v2 < 0) { throw new EndOfStreamException("unexpected end of stream."); } // Note: the oracle attack on the "quick check" bytes is deemed // a security risk for typical public key encryption usages, // therefore we do not perform the check. // bool repeatCheckPassed = // iv[iv.Length - 2] == (byte)v1 // && iv[iv.Length - 1] == (byte)v2; // // // Note: some versions of PGP appear to produce 0 for the extra // // bytes rather than repeating the two previous bytes // bool zeroesCheckPassed = // v1 == 0 // && v2 == 0; // // if (!repeatCheckPassed && !zeroesCheckPassed) // { // throw new PgpDataValidationException("quick check failed."); // } return(this.EncStream); } catch (PgpException) { throw; } catch (Exception e) { throw new PgpException("Exception starting decryption", e); } }