public override void AddSessionInfo( byte[] si, SecureRandom random) { string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm); IBufferedCipher c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding"); byte[] iv = new byte[c.GetBlockSize()]; c.Init(true, new ParametersWithRandom(new ParametersWithIV(key, iv), random)); this.sessionInfo = c.DoFinal(si, 0, si.Length - 2); }
private IBufferedCipher CreateStreamCipher( SymmetricKeyAlgorithmTag keyAlgorithm) { string mode = (encData is SymmetricEncIntegrityPacket) ? "CFB" : "OpenPGPCFB"; string cName = PgpUtilities.GetSymmetricCipherName(keyAlgorithm) + "/" + mode + "/NoPadding"; return(CipherUtilities.GetCipher(cName)); }
/// <summary> /// <p> /// If buffer is non null stream assumed to be partial, otherwise the length will be used /// to output a fixed length packet. /// </p> /// <p> /// The stream created can be closed off by either calling Close() /// on the stream or Close() on the generator. Closing the returned /// stream does not close off the Stream parameter <c>outStr</c>. /// </p> /// </summary> private Stream Open( Stream outStr, long length, byte[] buffer) { if (cOut != null) { throw new InvalidOperationException("generator already in open state"); } if (methods.Count == 0) { throw new InvalidOperationException("No encryption methods specified"); } if (outStr == null) { throw new ArgumentNullException("outStr"); } pOut = new BcpgOutputStream(outStr); KeyParameter key; if (methods.Count == 1) { if (methods[0] is PbeMethod) { PbeMethod m = (PbeMethod)methods[0]; key = m.GetKey(); } else { key = PgpUtilities.MakeRandomKey(defAlgorithm, rand); byte[] sessionInfo = CreateSessionInfo(defAlgorithm, key); PubMethod m = (PubMethod)methods[0]; try { m.AddSessionInfo(sessionInfo, rand); } catch (Exception e) { throw new PgpException("exception encrypting session key", e); } } pOut.WritePacket((ContainedPacket)methods[0]); } else // multiple methods { key = PgpUtilities.MakeRandomKey(defAlgorithm, rand); byte[] sessionInfo = CreateSessionInfo(defAlgorithm, key); for (int i = 0; i != methods.Count; i++) { EncMethod m = (EncMethod)methods[i]; try { m.AddSessionInfo(sessionInfo, rand); } catch (Exception e) { throw new PgpException("exception encrypting session key", e); } pOut.WritePacket(m); } } string cName = PgpUtilities.GetSymmetricCipherName(defAlgorithm); if (cName == null) { throw new PgpException("null cipher specified"); } try { if (withIntegrityPacket) { cName += "/CFB/NoPadding"; } else { cName += "/OpenPGPCFB/NoPadding"; } c = CipherUtilities.GetCipher(cName); // TODO Confirm the IV should be all zero bytes (not inLineIv - see below) byte[] iv = new byte[c.GetBlockSize()]; c.Init(true, new ParametersWithRandom(new ParametersWithIV(key, iv), rand)); if (buffer == null) { // // we have to Add block size + 2 for the Generated IV and + 1 + 22 if integrity protected // if (withIntegrityPacket) { pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, length + c.GetBlockSize() + 2 + 1 + 22); pOut.WriteByte(1); // version number } else { pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, length + c.GetBlockSize() + 2, oldFormat); } } else { if (withIntegrityPacket) { pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, buffer); pOut.WriteByte(1); // version number } else { pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, buffer); } } int blockSize = c.GetBlockSize(); byte[] inLineIv = new byte[blockSize + 2]; rand.NextBytes(inLineIv, 0, blockSize); Array.Copy(inLineIv, inLineIv.Length - 4, inLineIv, inLineIv.Length - 2, 2); Stream myOut = cOut = new CipherStream(pOut, null, c); if (withIntegrityPacket) { string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1); IDigest digest = DigestUtilities.GetDigest(digestName); myOut = digestOut = new DigestStream(myOut, null, digest); } myOut.Write(inLineIv, 0, inLineIv.Length); return(new WrappedGeneratorStream(this, myOut)); } catch (Exception e) { throw new PgpException("Exception creating cipher", e); } }
internal Stream DoGetDataStream(byte[] rawPassPhrase, bool clearPassPhrase) { try { SymmetricKeyAlgorithmTag keyAlgorithm = keyData.EncAlgorithm; KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase( keyAlgorithm, keyData.S2k, rawPassPhrase, clearPassPhrase); byte[] secKeyData = keyData.GetSecKeyData(); if (secKeyData != null && secKeyData.Length > 0) { IBufferedCipher keyCipher = CipherUtilities.GetCipher( PgpUtilities.GetSymmetricCipherName(keyAlgorithm) + "/CFB/NoPadding"); keyCipher.Init(false, new ParametersWithIV(key, new byte[keyCipher.GetBlockSize()])); byte[] keyBytes = keyCipher.DoFinal(secKeyData); keyAlgorithm = (SymmetricKeyAlgorithmTag)keyBytes[0]; key = ParameterUtilities.CreateKeyParameter( PgpUtilities.GetSymmetricCipherName(keyAlgorithm), keyBytes, 1, keyBytes.Length - 1); } IBufferedCipher c = CreateStreamCipher(keyAlgorithm); byte[] 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); string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1); IDigest 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."); } int v1 = encStream.ReadByte(); int 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) 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(encStream); } catch (PgpException e) { throw e; } catch (Exception e) { throw new PgpException("Exception creating cipher", e); } }
/// <summary>Return the decrypted data stream for the packet.</summary> public Stream GetDataStream( PgpPrivateKey privKey) { byte[] sessionData = RecoverSessionData(privKey); if (!ConfirmCheckSum(sessionData)) { throw new PgpKeyValidationException("key checksum failed"); } SymmetricKeyAlgorithmTag symmAlg = (SymmetricKeyAlgorithmTag)sessionData[0]; if (symmAlg == SymmetricKeyAlgorithmTag.Null) { return(encData.GetInputStream()); } IBufferedCipher cipher; string cipherName = PgpUtilities.GetSymmetricCipherName(symmAlg); string cName = cipherName; try { if (encData is SymmetricEncIntegrityPacket) { cName += "/CFB/NoPadding"; } else { cName += "/OpenPGPCFB/NoPadding"; } cipher = CipherUtilities.GetCipher(cName); } catch (PgpException e) { throw e; } catch (Exception e) { throw new PgpException("exception creating cipher", e); } try { KeyParameter key = ParameterUtilities.CreateKeyParameter( cipherName, sessionData, 1, sessionData.Length - 3); byte[] iv = new byte[cipher.GetBlockSize()]; cipher.Init(false, new ParametersWithIV(key, iv)); encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), cipher, null)); if (encData is SymmetricEncIntegrityPacket) { truncStream = new TruncatedStream(encStream); string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1); IDigest 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."); } int v1 = encStream.ReadByte(); int 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 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(encStream); } catch (PgpException e) { throw e; } catch (Exception e) { throw new PgpException("Exception starting decryption", e); } }