/// <summary>Return the decrypted input stream, using the passed in passphrase.</summary> public Stream GetDataStream( char[] passPhrase) { try { SymmetricKeyAlgorithmTag keyAlgorithm = keyData.EncAlgorithm; KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase( keyAlgorithm, keyData.S2k, passPhrase); 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); } }
private void GetSig() { this.sig = SignerUtilities.GetSigner( PgpUtilities.GetSignatureName(sigPck.KeyAlgorithm, sigPck.HashAlgorithm)); }
/// <summary>Return a signature object containing the current signature state.</summary> public PgpSignature Generate() { SignatureSubpacket[] hPkts = hashed, unhPkts = unhashed; if (!packetPresent(hashed, SignatureSubpacketTag.CreationTime)) { hPkts = insertSubpacket(hPkts, new SignatureCreationTime(false, DateTime.UtcNow)); } if (!packetPresent(hashed, SignatureSubpacketTag.IssuerKeyId) && !packetPresent(unhashed, SignatureSubpacketTag.IssuerKeyId)) { unhPkts = insertSubpacket(unhPkts, new IssuerKeyId(false, privKey.KeyId)); } int version = 4; byte[] hData; try { MemoryStream hOut = new MemoryStream(); for (int i = 0; i != hPkts.Length; i++) { hPkts[i].Encode(hOut); } byte[] data = hOut.ToArray(); MemoryStream sOut = new MemoryStream(data.Length + 6); sOut.WriteByte((byte)version); sOut.WriteByte((byte)signatureType); sOut.WriteByte((byte)keyAlgorithm); sOut.WriteByte((byte)hashAlgorithm); sOut.WriteByte((byte)(data.Length >> 8)); sOut.WriteByte((byte)data.Length); sOut.Write(data, 0, data.Length); hData = sOut.ToArray(); } catch (IOException e) { throw new PgpException("exception encoding hashed data.", e); } sig.BlockUpdate(hData, 0, hData.Length); dig.BlockUpdate(hData, 0, hData.Length); hData = new byte[] { (byte)version, 0xff, (byte)(hData.Length >> 24), (byte)(hData.Length >> 16), (byte)(hData.Length >> 8), (byte)hData.Length }; sig.BlockUpdate(hData, 0, hData.Length); dig.BlockUpdate(hData, 0, hData.Length); byte[] sigBytes = sig.GenerateSignature(); byte[] digest = DigestUtilities.DoFinal(dig); byte[] fingerPrint = new byte[] { digest[0], digest[1] }; // an RSA signature bool isRsa = keyAlgorithm == PublicKeyAlgorithmTag.RsaSign || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral; MPInteger[] sigValues = isRsa ? PgpUtilities.RsaSigToMpi(sigBytes) : PgpUtilities.DsaSigToMpi(sigBytes); return(new PgpSignature( new SignaturePacket(signatureType, privKey.KeyId, keyAlgorithm, hashAlgorithm, hPkts, unhPkts, fingerPrint, sigValues))); }
private byte[] ExtractKeyData( char[] passPhrase) { SymmetricKeyAlgorithmTag alg = secret.EncAlgorithm; byte[] encData = secret.GetSecretKeyData(); if (alg == SymmetricKeyAlgorithmTag.Null) { return(encData); } byte[] data; IBufferedCipher c = null; try { string cName = PgpUtilities.GetSymmetricCipherName(alg); c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding"); } catch (Exception e) { throw new PgpException("Exception creating cipher", e); } // TODO Factor this block out as 'encryptData' try { KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, passPhrase); byte[] iv = secret.GetIV(); if (secret.PublicKeyPacket.Version == 4) { c.Init(false, new ParametersWithIV(key, iv)); data = c.DoFinal(encData); bool useSha1 = secret.S2kUsage == SecretKeyPacket.UsageSha1; byte[] check = Checksum(useSha1, data, (useSha1) ? data.Length - 20 : data.Length - 2); for (int i = 0; i != check.Length; i++) { if (check[i] != data[data.Length - check.Length + i]) { throw new PgpException("Checksum mismatch at " + i + " of " + check.Length); } } } else // version 2 or 3, RSA only. { data = new byte[encData.Length]; // // read in the four numbers // int pos = 0; for (int i = 0; i != 4; i++) { c.Init(false, new ParametersWithIV(key, iv)); int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8; data[pos] = encData[pos]; data[pos + 1] = encData[pos + 1]; pos += 2; c.DoFinal(encData, pos, encLen, data, pos); pos += encLen; if (i != 3) { Array.Copy(encData, pos - iv.Length, iv, 0, iv.Length); } } // // verify Checksum // int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff); int calcCs = 0; for (int j = 0; j < data.Length - 2; j++) { calcCs += data[j] & 0xff; } calcCs &= 0xffff; if (calcCs != cs) { throw new PgpException("Checksum mismatch: passphrase wrong, expected " + cs.ToString("X") + " found " + calcCs.ToString("X")); } } return(data); } catch (PgpException e) { throw e; } catch (Exception e) { throw new PgpException("Exception decrypting key", e); } }