/// <summary> /// Pads the signature with extra data. /// </summary> /// <param name="signature">The signature.</param> /// <param name="outputStream">The padded signature.</param> /// <param name="extra">The extra data passed by sigData.</param> protected override void PadSignature(byte[] signature, Stream outputStream, object extra) { var padData = (Tuple <long, long, Stream>)extra; var stopLength = padData.Item1; var position = padData.Item2; var input = padData.Item3; var key = GetPrimaryKey() as ISignerKey; outputStream.Write(FormatBytes, 0, FormatBytes.Length); outputStream.Write(key.GetKeyHash(), 0, KeyHashLength); var lengthBytes = Utility.GetBytes((int)(stopLength - position)); outputStream.Write(lengthBytes, 0, lengthBytes.Length); padData.Item3.Seek(position, SeekOrigin.Begin); using (var reader = new NondestructiveBinaryReader(input)) { var adjustedBufferSize = (int)Math.Min(BufferSize, (stopLength - input.Position)); while (reader.Peek() != -1 && input.Position < stopLength) { byte[] buffer = reader.ReadBytes(adjustedBufferSize); outputStream.Write(buffer, 0, buffer.Length); } } outputStream.Write(signature, 0, signature.Length); }
/// <summary> /// Signs the specified data. /// </summary> /// <param name="input">The input.</param> /// <param name="outstream">The outstream.</param> /// <param name="prefixData">The prefix data.</param> /// <param name="postfixData">The postfix data.</param> /// <param name="signatureData">The sig data.</param> /// <param name="inputLength"> Length of the input.</param> protected void Sign(Stream input, Stream outstream, object prefixData, object postfixData, object signatureData, long inputLength) { var stopLength = inputLength < 0 ? long.MaxValue : input.Position + inputLength; if (!(GetPrimaryKey() is ISignerKey key)) { throw MakeInvalidKeySetTypeException(); } using (var reader = new NondestructiveBinaryReader(input)) { using (var signingStream = key.GetSigningStream(this)) { PrefixDataSign(signingStream, prefixData); while (reader.Peek() != -1 && input.Position < stopLength) { var adjustedBufferSize = (int)Math.Min(BufferSize, (stopLength - input.Position)); byte[] buffer = reader.ReadBytes(adjustedBufferSize); signingStream.Write(buffer, 0, buffer.Length); } PostfixDataSign(signingStream, postfixData); signingStream.Finish(); var signature = signingStream.HashValue; PadSignature(signature, outstream, signatureData); } } }
public bool Verify(Stream input, byte[] signature, long inputLength = -1) { var milliseconds = FromDateTime(_currentDateTime()); if (!_verifier.Verify(input, signature, inputLength)) { return(false); } using (var stream = new MemoryStream(signature)) using (var reader = new NondestructiveBinaryReader(stream)) { reader.ReadBytes(HeaderLength); var expiration = reader.ReadBytes(TimeoutLength); var expMilliseconds = Utility.ToInt64(expiration); return(milliseconds < expMilliseconds); } }
public bool VerifyHidden(Stream input, Stream verifiedMessage, byte[] hidden, long inputLength) { var fullLength = inputLength < 0 ? input.Length : inputLength + input.Position; using (var reader = new NondestructiveBinaryReader(input)) { var header = reader.ReadBytes(KeyczarConst.HeaderLength); var length = Utility.ToInt32(reader.ReadBytes(4)); if (fullLength < input.Position + length) { throw new InvalidCryptoDataException("Data doesn't appear to have signatures attached!"); } using (var sigStream = new MemoryStream()) { using (Utility.ResetStreamWhenFinished(input)) { sigStream.Write(header, 0, header.Length); input.Seek(length, SeekOrigin.Current); while (reader.Peek() != -1 && input.Position < fullLength) { var adjustedBufferSize = (int)Math.Min(BufferSize, (fullLength - input.Position)); var buffer = reader.ReadBytes(adjustedBufferSize); sigStream.Write(buffer, 0, buffer.Length); } sigStream.Flush(); } using (var signedMessageLimtedLength = new NondestructivePositionLengthLimitingStream(input)) { signedMessageLimtedLength.SetLength(length); if (verifiedMessage != null) { using (Utility.ResetStreamWhenFinished(input)) { signedMessageLimtedLength.CopyTo(verifiedMessage); } } var verified = Verify(signedMessageLimtedLength, sigStream.ToArray(), prefixData: null, postfixData: hidden, inputLength: inputLength); input.Seek(fullLength, SeekOrigin.Begin); return(verified); } } } }
/// <summary> /// Verifies the specified data. /// </summary> /// <param name="input">The input.</param> /// <param name="signature">The signature.</param> /// <param name="prefixData">The prefix data.</param> /// <param name="postfixData">The postfix data.</param> /// <param name="inputLength">(optional) Length of the input.</param> /// <returns></returns> protected virtual bool Verify(Stream input, byte[] signature, object prefixData, object postfixData, long inputLength) { var stopLength = inputLength < 0 ? long.MaxValue : input.Position + inputLength; using (var reader = new NondestructiveBinaryReader(input)) { byte[] trimmedSig; var resetData = Utility.ResetStreamWhenFinished(input); foreach (var key in GetKeys(signature, out trimmedSig)) { resetData.Reset(); //in case there aren't any keys that match that hash we are going to fake verify. using (var verifyStream = key.Maybe(m => m.GetVerifyingStream(), () => new DummyStream())) { PrefixDataVerify(verifyStream, prefixData); while (reader.Peek() != -1 && input.Position < stopLength) { var adjustedBufferSize = (int)Math.Min(BufferSize, (stopLength - input.Position)); byte[] buffer = reader.ReadBytes(adjustedBufferSize); verifyStream.Write(buffer, 0, buffer.Length); } PostfixDataVerify(verifyStream, postfixData); try { if (verifyStream.VerifySignature(trimmedSig)) { return(true); } } catch (Exception e) { //We don't want exceptions to keep us from trying different keys System.Diagnostics.Debug.WriteLine(e.Message); System.Diagnostics.Debug.WriteLine(e.StackTrace); } } } return(false); } }
/// <summary> /// Decrypts the specified input. /// </summary> /// <param name="input">The input.</param> /// <param name="output">The output.</param> /// <param name="inputLength">(optional) Length of the input.</param> /// <exception cref="InvalidCryptoDataException">Ciphertext was invalid!</exception> public void Decrypt(Stream input, Stream output, long inputLength = -1) { var fullLength = inputLength < 0 ? input.Length : inputLength + input.Position; using (var reader = new NondestructiveBinaryReader(input)) { byte[] keyHash; var resetStream = Utility.ResetStreamWhenFinished(input); var header = Utility.ReadHeader(input, out keyHash); var verify = false; foreach (var key in GetKey(keyHash)) { var cryptKey = key as ICrypterKey; resetStream.Reset(); bool ciphertextIsPreverified = false; //in case there aren't any keys that match that hash we are going to fake verify. using (var verifyStream = cryptKey.Maybe(m => m.GetAuthVerifyingStream(this), () => new DummyStream())) { //If we verify in once pass like with AEAD verify stream will be null; if (verifyStream != null) { //Perform ciphertext verification ciphertextIsPreverified = true; var tagLength = verifyStream.GetTagLength(header); while (input.Position < fullLength - tagLength) { byte[] buffer = reader.ReadBytes((int)Math.Min(BufferSize, fullLength - tagLength - input.Position)); verifyStream.Write(buffer, 0, buffer.Length); } var signature = reader.ReadBytes(tagLength); try { verify = verifyStream.VerifySignature(signature); } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.Message); System.Diagnostics.Debug.WriteLine(e.StackTrace); //We don't want exceptions to keep us from trying different keys verify = false; } } } if ((!verify && ciphertextIsPreverified) || input.Length == 0) { continue; } // Stream baseStream = ciphertextIsPreverified ? output : new MemoryStream(); Stream wrapper = baseStream; bool success = false; if (Compression == CompressionType.Gzip) { wrapper = new WriteDecompressGzipStream(baseStream); } else if (Compression == CompressionType.Zlib) { wrapper = new ZlibStream(baseStream, CompressionMode.Decompress, true); } //Perform Decryption using (Compression == CompressionType.None ? null : wrapper){ FinishingStream crypterStream; resetStream.Reset(); input.Seek(KeyczarConst.HeaderLength, SeekOrigin.Current); crypterStream = cryptKey.Maybe(m => m.GetDecryptingStream(wrapper, this), () => new DummyStream()); try { using (crypterStream) { var tagLength = crypterStream.GetTagLength(header); while (input.Position < fullLength - tagLength) { byte[] buffer = reader.ReadBytes((int)Math.Min(BufferSize, fullLength - tagLength - input.Position)); crypterStream.Write(buffer, 0, buffer.Length); } crypterStream.Finish(); input.Seek(tagLength, SeekOrigin.Current); success = true; } } catch (Exception e) { //We don't want exceptions to keep us from trying different keys //particularly ones that aren't pre verified System.Diagnostics.Debug.WriteLine(e.Message); System.Diagnostics.Debug.WriteLine(e.StackTrace); } } if (success) { if (!ciphertextIsPreverified) { //If the ciphertext is verified in one pass, //we have to make sure that verification was successful before copying it to output. baseStream.Seek(0, SeekOrigin.Begin); baseStream.CopyTo(output); } return; } } throw new InvalidCryptoDataException("Cipher text was invalid!"); } }
public void Encrypt(Stream input, Stream output, long inputLength = -1) { var stopLength = inputLength < 0 ? long.MaxValue : input.Position + inputLength; var key = GetPrimaryKey(); var header = new byte[HeaderLength]; Array.Copy(FormatBytes, 0, header, 0, FormatBytes.Length); Array.Copy(key.GetKeyHash(), 0, header, FormatBytes.Length, KeyHashLength); var cryptKey = key as IEncrypterKey; var resetStream = Utility.ResetStreamWhenFinished(output); using (var reader = new NondestructiveBinaryReader(input)) { FinishingStream encryptingStream; output.Write(header, 0, header.Length); encryptingStream = cryptKey.GetEncryptingStream(output); Stream wrapper = encryptingStream; if (Compression == CompressionType.Gzip) { wrapper = new GZipStream(encryptingStream, CompressionMode.Compress, true); } else if (Compression == CompressionType.Zlib) { wrapper = new ZlibStream(encryptingStream, CompressionMode.Compress, true); } using (encryptingStream) { encryptingStream.GetTagLength(header); using (Compression == CompressionType.None ? null : wrapper){ while (reader.Peek() != -1 && input.Position < stopLength) { var adjustedBufferSize = (int)Math.Min(BufferSize, (stopLength - input.Position)); byte[] buffer = reader.ReadBytes(adjustedBufferSize); wrapper.Write(buffer, 0, buffer.Length); } } encryptingStream.Finish(); } } byte[] hash; using (var outputReader = new NondestructiveBinaryReader(output)) using (var signingStream = cryptKey.GetAuthSigningStream()) { if (signingStream == null || signingStream.GetTagLength(header) == 0) { return; } resetStream.Reset(); while (outputReader.Peek() != -1) { byte[] buffer = outputReader.ReadBytes(BufferSize); signingStream.Write(buffer, 0, buffer.Length); } signingStream.Finish(); hash = signingStream.HashValue; } output.Write(hash, 0, hash.Length); }