public void CheckE(string testName, byte[] key, byte[] data, byte[] result) { algo = new HMACSHA256(); algo.Key = key; byte [] copy = new byte [data.Length]; // LAMESPEC or FIXME: TransformFinalBlock doesn't return HashValue ! for (int i = 0; i < data.Length - 1; i++) { algo.TransformBlock(data, i, 1, copy, i); } algo.TransformFinalBlock(data, data.Length - 1, 1); AreEqual(result, algo.Hash, testName + "e"); }
private void WriteSafeBlock() { byte[] pbBlockIndex = MemUtil.UInt64ToBytes(m_uBlockIndex); int cbBlockSize = m_iBufferPos; byte[] pbBlockSize = MemUtil.Int32ToBytes(cbBlockSize); byte[] pbBlockHmac; byte[] pbBlockKey = GetHmacKey64(m_pbKey, m_uBlockIndex); using (HMACSHA256 h = new HMACSHA256(pbBlockKey)) { h.TransformBlock(pbBlockIndex, 0, pbBlockIndex.Length, pbBlockIndex, 0); h.TransformBlock(pbBlockSize, 0, pbBlockSize.Length, pbBlockSize, 0); if (cbBlockSize != 0) { h.TransformBlock(m_pbBuffer, 0, cbBlockSize, m_pbBuffer, 0); } h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); pbBlockHmac = h.Hash; } MemUtil.ZeroByteArray(pbBlockKey); MemUtil.Write(m_sBase, pbBlockHmac); // MemUtil.Write(m_sBase, pbBlockIndex); // Implicit MemUtil.Write(m_sBase, pbBlockSize); if (cbBlockSize != 0) { m_sBase.Write(m_pbBuffer, 0, cbBlockSize); } ++m_uBlockIndex; m_iBufferPos = 0; }
private static (byte, byte[]) EncryptData(Stream inStream, Stream outStream, byte[] internalKey, byte[] iv, int bufferSize) { var lastDataReadSize = 0; // File size modulo 16 in least significant byte positions using (var cipher = CreateAes(internalKey, iv)) using (var ms = new MemoryStream()) using (var cryptoStream = new CryptoStream(ms, cipher.CreateEncryptor(), CryptoStreamMode.Write)) { int bytesRead; var buffer = new byte[bufferSize]; while ((bytesRead = inStream.Read(buffer, 0, buffer.Length)) > 0) { cryptoStream.Write(buffer, 0, bytesRead); if (bytesRead < bufferSize) { lastDataReadSize = bytesRead % AesBlockSize; if (lastDataReadSize != 0) { var padLen = 16 - bytesRead % AesBlockSize; var padding = new byte[padLen]; padding.Fill((byte)padLen); cryptoStream.Write(padding, 0, padding.Length); } } } cryptoStream.FlushFinalBlock(); ms.Position = 0; using (var hmac0 = new HMACSHA256(internalKey)) { hmac0.Initialize(); while ((bytesRead = ms.Read(buffer, 0, buffer.Length)) > 0) { outStream.Write(buffer, 0, bytesRead); hmac0.TransformBlock(buffer, 0, bytesRead, null, 0); } hmac0.TransformFinalBlock(Array.Empty <byte>(), 0, 0); return((byte)lastDataReadSize, hmac0.Hash); } } }
private void OnBufferReady(byte[] buffer) { if (!_secure) { ProcessFrame(buffer, _offset, _bytesToBuffer); return; } if (_bytesToBuffer == PREFIX_SIZE) { byte[] size = new byte[2]; _decryptor.TransformBlock(_buffer, _offset + HMAC_SIZE, 2, size, 0); _bytesToBuffer += BitConverter.ToUInt16(size, 0); } else { byte[] counter = BitConverter.GetBytes(_inCounter++); _verifier.TransformBlock(counter, 0, counter.Length, null, 0); _verifier.TransformFinalBlock(_buffer, _offset + HMAC_SIZE, _bytesToBuffer - HMAC_SIZE); if (!CompareBytes(_verifier.Hash, 0, _buffer, _offset, HMAC_SIZE)) { OnExceptionThrown(new InvalidDataException("Invalid record signature.")); return; } _verifier.Initialize(); _decryptor.TransformBlock(_buffer, _offset + PREFIX_SIZE, _bytesToBuffer - PREFIX_SIZE, _buffer, _offset + PREFIX_SIZE); if (_state == FrameState.Established) { OnDataDecoded(buffer, _offset + PREFIX_SIZE, _bytesToBuffer - PREFIX_SIZE); _bufferPosition = 0; _bytesToBuffer = PREFIX_SIZE; } else { ProcessFrame(buffer, _offset + PREFIX_SIZE, _bytesToBuffer - PREFIX_SIZE); } } }
private static string CalculateSha256Hash(string key, string msg1, string msg2) { byte[] encodedKey = Encoding.UTF8.GetBytes(key); byte[] encodedMsg1 = Encoding.UTF8.GetBytes(msg1); byte[] encodedMsg2 = Encoding.UTF8.GetBytes(msg2); HMACSHA256 hmac = new HMACSHA256(encodedKey); hmac.TransformBlock(encodedMsg1, 0, encodedMsg1.Length, null, 0); hmac.TransformFinalBlock(encodedMsg2, 0, encodedMsg2.Length); StringBuilder sb = new StringBuilder(); foreach (byte b in hmac.Hash) { sb.Append(b.ToString("x2")); } return(sb.ToString()); }
public static byte[] ComputeHMACSHA256HashFromFile(string filePath, byte[] authKey, long startPosition, long endPosition) { byte[] hash = null; using (var fStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None)) { fStream.Position = startPosition; byte[] buffer = new byte[(1024 * 4)]; long amount = (endPosition - startPosition); using (var hmacSha256 = new HMACSHA256(authKey)) { while (amount > 0) { int bytesRead = fStream.Read(buffer, 0, (int)Math.Min(buffer.Length, amount)); if (bytesRead > 0) { amount -= bytesRead; if (amount > 0) { hmacSha256.TransformBlock(buffer, 0, bytesRead, buffer, 0); } else { hmacSha256.TransformFinalBlock(buffer, 0, bytesRead); } } else { throw new InvalidOperationException(); } } hash = hmacSha256.Hash; } } return(hash); }
private string Sign <T>(string key, Message <T> ioPubMessage, List <string> messages, NetMQSocket iopub) { var encoder = new UTF8Encoding(); var hMAC = new HMACSHA256(encoder.GetBytes(key)); hMAC.Initialize(); // https://jupyter-client.readthedocs.io/en/stable/messaging.html#the-wire-protocol messages.Add(JsonConvert.SerializeObject(ioPubMessage.Header)); messages.Add(JsonConvert.SerializeObject(ioPubMessage.ParentHeader)); messages.Add(JsonConvert.SerializeObject(ioPubMessage.Metadata)); messages.Add(JsonConvert.SerializeObject(ioPubMessage.Content)); // signature foreach (string item in messages) { var sourceBytes = encoder.GetBytes(item); hMAC.TransformBlock(sourceBytes, 0, sourceBytes.Length, null, 0); } hMAC.TransformFinalBlock(new byte[0], 0, 0); return(BitConverter.ToString(hMAC.Hash).Replace("-", "").ToLower()); }
private bool ReadSafeBlock() { if (m_bEos) { return(false); // End of stream reached already } byte[] pbStoredHmac = MemUtil.Read(m_sBase, 32); if ((pbStoredHmac == null) || (pbStoredHmac.Length != 32)) { throw new EndOfStreamException(KLRes.FileCorrupted + " " + KLRes.FileIncomplete); } // Block index is implicit: it's used in the HMAC computation, // but does not need to be stored // byte[] pbBlockIndex = MemUtil.Read(m_sBase, 8); // if((pbBlockIndex == null) || (pbBlockIndex.Length != 8)) // throw new EndOfStreamException(); // ulong uBlockIndex = MemUtil.BytesToUInt64(pbBlockIndex); // if((uBlockIndex != m_uBlockIndex) && m_bVerify) // throw new InvalidDataException(); byte[] pbBlockIndex = MemUtil.UInt64ToBytes(m_uBlockIndex); byte[] pbBlockSize = MemUtil.Read(m_sBase, 4); if ((pbBlockSize == null) || (pbBlockSize.Length != 4)) { throw new EndOfStreamException(KLRes.FileCorrupted + " " + KLRes.FileIncomplete); } int nBlockSize = MemUtil.BytesToInt32(pbBlockSize); if (nBlockSize < 0) { throw new InvalidDataException(KLRes.FileCorrupted); } m_iBufferPos = 0; SetBuffer(MemUtil.Read(m_sBase, nBlockSize)); if ((m_pbBuffer == null) || ((m_pbBuffer.Length != nBlockSize) && m_bVerify)) { throw new EndOfStreamException(KLRes.FileCorrupted + " " + KLRes.FileIncompleteExpc); } if (m_bVerify) { byte[] pbCmpHmac; byte[] pbBlockKey = GetHmacKey64(m_pbKey, m_uBlockIndex); using (HMACSHA256 h = new HMACSHA256(pbBlockKey)) { h.TransformBlock(pbBlockIndex, 0, pbBlockIndex.Length, pbBlockIndex, 0); h.TransformBlock(pbBlockSize, 0, pbBlockSize.Length, pbBlockSize, 0); if (m_pbBuffer.Length != 0) { h.TransformBlock(m_pbBuffer, 0, m_pbBuffer.Length, m_pbBuffer, 0); } h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); pbCmpHmac = h.Hash; } MemUtil.ZeroByteArray(pbBlockKey); if (!MemUtil.ArraysEqual(pbCmpHmac, pbStoredHmac)) { throw new InvalidDataException(KLRes.FileCorrupted); } } ++m_uBlockIndex; if (nBlockSize == 0) { m_bEos = true; return(false); // No further data available } return(true); }
/// <summary>Encrypts files using a key or the supplied password.</summary> /// <remarks> /// The original file is not modified; a new encrypted file is created. /// The password is not required if a master key has been set /// (either with `RandomKeyGgen` or with `SetMasterKey`). /// If a password is supplied, it will be used to create a key with PBKDF2. /// </remarks> /// <param name="path">The file path.</param> /// <param name="password">Optional, the pasword.</param> /// <returns>The encrypted file path.</returns> public string EncryptFile(string path, string password = null) { byte[] salt = RandomBytes(saltLen); byte[] iv = RandomBytes(ivLen); try { byte[][] keys = this.Keys(salt, password); byte[] aesKey = keys[0], macKey = keys[1]; string newPath = path + ".enc"; using (FileStream fs = new FileStream(newPath, FileMode.Create, FileAccess.Write)) { fs.Write(salt, 0, saltLen); fs.Write(iv, 0, ivLen); RijndaelManaged cipher = this.Cipher(aesKey, iv); ICryptoTransform ict = cipher.CreateEncryptor(); HMACSHA256 hmac = new HMACSHA256(macKey); hmac.TransformBlock(iv, 0, iv.Length, null, 0); foreach (Object[] chunk in FileChunks(path)) { byte[] data = (byte[])chunk[0]; byte[] ciphertext = new byte[data.Length]; if ((bool)chunk[1]) { ciphertext = ict.TransformFinalBlock(data, 0, data.Length); } else { ict.TransformBlock(data, 0, data.Length, ciphertext, 0); } hmac.TransformBlock(ciphertext, 0, ciphertext.Length, null, 0); fs.Write(ciphertext, 0, ciphertext.Length); } hmac.TransformFinalBlock(new byte[0], 0, 0); byte[] mac = hmac.Hash; fs.Write(mac, 0, mac.Length); ict.Dispose(); cipher.Dispose(); hmac.Dispose(); } return(newPath); } catch (ArgumentException e) { this.ErrorHandler(e); } catch (CryptographicException e) { this.ErrorHandler(e); } catch (UnauthorizedAccessException e) { this.ErrorHandler(e); } catch (IOException e) { this.ErrorHandler(e); } return(null); }
private static void DecryptData(Stream inStream, Stream outStream, byte[] key, byte[] ivMain, byte[] mainKeyAndIv, int bufferSize) { var(dataIv, internalKey) = DecryptMainKeyAndIv(key, ivMain, mainKeyAndIv); var currentPosition = inStream.Position; var endPositionEncryptedData = inStream.Length - 32 - 1; // Get padding and hmac inStream.Position = endPositionEncryptedData; var padding = (16 - ReadBytes(inStream, 1)[0]) % 16; var hmacEncryptedData = ReadBytes(inStream, 32); // Reset the position to the beginning of the encrypted data inStream.Position = currentPosition; // Get hmac using (var hmac0 = new HMACSHA256(internalKey)) { hmac0.Initialize(); // Get the cipher using (var cipher = CreateAes(internalKey, dataIv)) using (var decrypter = cipher.CreateDecryptor()) { // First read as much data as possible. ReadEncryptedBytes(bufferSize); // read the remaining ReadEncryptedBytes(); // Everything read but the last block need to remove padding if (inStream.Position != endPositionEncryptedData) { var lastBlock = ReadBytes(inStream, AesBlockSize); hmac0.TransformBlock(lastBlock, 0, lastBlock.Length, null, 0); decrypter.TransformBlock(lastBlock, 0, lastBlock.Length, lastBlock, 0); outStream.Write(lastBlock, 0, lastBlock.Length - padding); } decrypter.TransformFinalBlock(Array.Empty <byte>(), 0, 0); hmac0.TransformFinalBlock(Array.Empty <byte>(), 0, 0); if (!hmac0.Hash.SequenceEqual(hmacEncryptedData)) { throw new InvalidOperationException(Resources.TheFileIsCorrupt); } // Functions void ReadEncryptedBytes(int bytesToRead = AesBlockSize) { var buffer = new byte[bytesToRead]; while (inStream.Position < endPositionEncryptedData - bytesToRead) { var bytesRead = inStream.Read(buffer, 0, buffer.Length); hmac0.TransformBlock(buffer, 0, bytesRead, null, 0); decrypter.TransformBlock(buffer, 0, bytesRead, buffer, 0); outStream.Write(buffer, 0, buffer.Length); } } } } }
public static Document Load(Stream stream, byte[] passphraseBuffer) { if (stream == null) { throw new ArgumentNullException(nameof(stream), "Stream cannot be null."); } if (passphraseBuffer == null) { throw new ArgumentNullException(nameof(passphraseBuffer), "Passphrase cannot be null."); } var buffer = new byte[16384]; using (var ms = new MemoryStream()) { int read; while ((read = stream.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, read); } buffer = ms.ToArray(); } if ((buffer.Length < 200) || (BitConverter.ToInt32(buffer, 0) != Tag) || (BitConverter.ToInt32(buffer, buffer.Length - 32 - 16) != Tag) || (BitConverter.ToInt32(buffer, buffer.Length - 32 - 12) != TagEof) || (BitConverter.ToInt32(buffer, buffer.Length - 32 - 8) != Tag) || (BitConverter.ToInt32(buffer, buffer.Length - 32 - 4) != TagEof)) { throw new FormatException("Unrecognized file format."); } var salt = new byte[32]; Buffer.BlockCopy(buffer, 4, salt, 0, salt.Length); var iter = BitConverter.ToUInt32(buffer, 36); byte[] stretchedKey = null, keyK = null, keyL = null, data = null; try { stretchedKey = GetStretchedKey(passphraseBuffer, salt, iter); if (!AreBytesTheSame(GetSha256Hash(stretchedKey), buffer, 40)) { throw new CryptographicException("Password mismatch."); } keyK = DecryptKey(stretchedKey, buffer, 72); keyL = DecryptKey(stretchedKey, buffer, 104); var iv = new byte[16]; Buffer.BlockCopy(buffer, 136, iv, 0, iv.Length); data = DecryptData(keyK, iv, buffer, 152, buffer.Length - 200); using (var dataHash = new HMACSHA256(keyL)) { var dataOffset = 0; var headerFields = new List <Header>(); while (dataOffset < data.Length) { var fieldLength = BitConverter.ToInt32(data, dataOffset + 0); var fieldLengthFull = ((fieldLength + 5 - 1) / 16 + 1) * 16; var fieldType = (HeaderType)data[dataOffset + 4]; var fieldData = new byte[fieldLength]; try { Buffer.BlockCopy(data, dataOffset + 5, fieldData, 0, fieldLength); dataOffset += fieldLengthFull; //there is ALWAYS some random bytes added, thus extra block if 16 bytes dataHash.TransformBlock(fieldData, 0, fieldData.Length, null, 0); //not hashing length nor type - wtf? if (fieldType == HeaderType.EndOfEntry) { break; } headerFields.Add(new Header(fieldType, fieldData)); } finally { Array.Clear(fieldData, 0, fieldData.Length); } } if ((headerFields.Count == 0) || (headerFields[0].Version < 0x0300)) { throw new FormatException("Unrecognized file format version."); } var recordFields = new List <List <Record> >(); List <Record> records = null; while (dataOffset < data.Length) { var fieldLength = BitConverter.ToInt32(data, dataOffset + 0); var fieldLengthFull = ((fieldLength + 5 - 1) / 16 + 1) * 16; var fieldType = (RecordType)data[dataOffset + 4]; var fieldData = new byte[fieldLength]; try { Buffer.BlockCopy(data, dataOffset + 5, fieldData, 0, fieldLength); dataOffset += fieldLengthFull; //there is ALWAYS some random bytes added, thus extra block if 16 bytes dataHash.TransformBlock(fieldData, 0, fieldData.Length, null, 0); //not hashing length nor type - wtf? if (fieldType == RecordType.EndOfEntry) { records = null; continue; } if (records == null) { records = new List <Record>(); recordFields.Add(records); } records.Add(new Record(fieldType, fieldData)); } finally { Array.Clear(fieldData, 0, fieldData.Length); } } dataHash.TransformFinalBlock(new byte[] { }, 0, 0); if (!AreBytesTheSame(dataHash.Hash, buffer, buffer.Length - 32)) { throw new CryptographicException("Authentication mismatch."); } var document = new Document(headerFields, recordFields.ToArray()) { _iterations = (int)iter, //to avoid rounding up if iteration count is less than 2048 Passphrase = passphraseBuffer //to avoid keeping password in memory for save - at least we don't need to deal with string's immutability. }; return(document); } } catch (CryptographicException ex) { throw new FormatException(ex.Message, ex); } finally { //best effort to sanitize memory if (stretchedKey != null) { Array.Clear(stretchedKey, 0, stretchedKey.Length); } if (keyK != null) { Array.Clear(keyK, 0, keyK.Length); } if (keyL != null) { Array.Clear(keyL, 0, keyL.Length); } if (data != null) { Array.Clear(data, 0, data.Length); } } }
private void button2_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() == DialogResult.OK) { SaveFileDialog sfd = new SaveFileDialog(); if (sfd.ShowDialog() == DialogResult.OK) { try { byte[] AES_KEY = { 0xB4, 0xEB, 0x7F, 0xB9, 0xA9, 0xAC, 0x05, 0x92, 0xAB, 0x8E, 0x42, 0xAB, 0xCC, 0x61, 0xD0, 0xC0 }; byte[] HMAC_KEY = { 0x82, 0xF4, 0x1A, 0x4F, 0x03, 0x45, 0x65, 0x01, 0x2F, 0x73, 0x9C, 0x4D, 0x8E, 0x63, 0xA9, 0x1F, 0xB9, 0x2B, 0x9D, 0x4E, 0xE1, 0x11, 0x91, 0x47, 0xD4, 0x3C, 0xC6, 0x88, 0x3F, 0xC7, 0xFC, 0x70 }; BinaryReader reader = new BinaryReader(new FileStream(ofd.FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)); BinaryWriter writer = new BinaryWriter(new FileStream(sfd.FileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite)); byte[] ProfileID = HexStringToByteArray(textBox1.Text); if (reader.ReadUInt32() != 0x73736D63) { throw new Exception("Invalid File"); } uint ReadSize = BSwapUint(reader.ReadUInt32()); byte[] Hash = reader.ReadBytes(0x20); uint DataSizeEnc = BSwapUint(reader.ReadUInt32()); byte[] AES_IV = reader.ReadBytes(0x10); uint DataSizeDec = DecryptDataSize(AES_IV, DataSizeEnc); byte[] DataBuffer = reader.ReadBytes((int)(DataSizeDec)); XorAes(ref AES_KEY, ProfileID, 1); AesCryptoServiceProvider aes = new AesCryptoServiceProvider(); aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.None; byte[] Encrypted = aes.CreateEncryptor(AES_KEY, AES_IV).TransformFinalBlock(DataBuffer, 0, DataBuffer.Length); XorHmac(ref HMAC_KEY, ProfileID, 0); HMACSHA256 hmac = new HMACSHA256(HMAC_KEY); byte[] Tmp = new byte[0x14]; Buffer.BlockCopy(BitConverter.GetBytes(BSwapUint(DataSizeEnc)), 0, Tmp, 0, 4); Buffer.BlockCopy(AES_IV, 0, Tmp, 4, 0x10); hmac.TransformBlock(Tmp, 0, 0x14, null, 0); hmac.TransformFinalBlock(Encrypted, 0, Encrypted.Length); writer.Write(0x73736D63); writer.Write(BSwapUint(ReadSize)); writer.Write(hmac.Hash); writer.Write(BSwapUint(DataSizeEnc)); writer.Write(AES_IV); writer.Write(Encrypted); writer.Flush(); writer.Close(); reader.Close(); } catch (Exception x) { MessageBox.Show(x.Message); } } } }
public static byte[] Pbkdf2(byte[] password, byte[] salt, int iterations = Pbkdf2Iterations) { /* * // Algorithm Credits to https://github.com/vexocide * // * // Implements PBKDF2WithHmacSHA256 in Java. Beautifully Amazing. * using (var mac = new HMACSHA256(password)) * { * mac.TransformBlock(salt, 0, salt.Length, salt, 0); * byte[] i = { 0, 0, 0, 1 }; * mac.TransformFinalBlock(i, 0, i.Length); * byte[] t = mac.Hash; * mac.Initialize(); * * byte[] u = t; * for (uint c = 2; c <= iterations; c++) * { * t = mac.ComputeHash(t); * for (int j = 0; j < mac.HashSize / 8; j++) * { * u[j] ^= t[j]; * } * } * * return u; * } */ #if STANDARD using (var macSalt = IncrementalHash.CreateHMAC(HashAlgorithmName.SHA256, password)) #endif using (var mac = new HMACSHA256(password)) { #if STANDARD macSalt.AppendData(salt); #else mac.TransformBlock(salt, 0, salt.Length, salt, 0); #endif byte[] i = { 0, 0, 0, 1 }; #if STANDARD macSalt.AppendData(i); #else mac.TransformFinalBlock(i, 0, i.Length); #endif #if STANDARD byte[] t = macSalt.GetHashAndReset(); #else byte[] t = mac.Hash; mac.Initialize(); #endif byte[] u = t; for (uint c = 2; c <= iterations; c++) { t = mac.ComputeHash(t); for (int j = 0; j < mac.HashSize / 8; j++) { u[j] ^= t[j]; } } return(u); } }
private void InternalEnqueue(IBufferWriter <byte> bufferWriter, Action <IBufferWriter <byte> > action) { using var hub = new Hub(); action.Invoke(hub.Writer); hub.Writer.Complete(); var sequence = hub.Reader.GetSequence(); try { if (_version.HasFlag(OmniSecureConnectionVersion.Version1) && _infoV1 != null) { if (_infoV1.CryptoAlgorithm.HasFlag(V1.Internal.CryptoAlgorithm.Aes_256) && _infoV1.HashAlgorithm.HasFlag(V1.Internal.HashAlgorithm.Sha2_256)) { const int headerSize = 8; const int blockSize = 16; // 送信済みデータ + 送信するデータのサイズを書き込む { var paddingSize = blockSize; if (sequence.Length % blockSize != 0) { paddingSize = blockSize - (int)(sequence.Length % blockSize); } var encryptedContentLength = blockSize + (sequence.Length + paddingSize); BinaryPrimitives.TryWriteUInt64BigEndian(bufferWriter.GetSpan(headerSize), (ulong)(_totalSentSize + encryptedContentLength)); bufferWriter.Advance(headerSize); } using (var hmac = new HMACSHA256(_infoV1.MyHmacKey)) using (var aes = Aes.Create()) { aes.KeySize = 256; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; // IVを書き込む var iv = new byte[blockSize]; _random.GetBytes(iv); bufferWriter.Write(iv); hmac.TransformBlock(iv, 0, iv.Length, null, 0); Interlocked.Add(ref _totalSentSize, iv.Length); // 暗号化データを書き込む using (var encryptor = aes.CreateEncryptor(_infoV1.MyCryptoKey, iv)) { var inBuffer = _bufferPool.GetArrayPool().Rent(blockSize); var outBuffer = _bufferPool.GetArrayPool().Rent(blockSize); try { while (sequence.Length > blockSize) { sequence.Slice(0, blockSize).CopyTo(inBuffer.AsSpan(0, blockSize)); var transed = encryptor.TransformBlock(inBuffer, 0, blockSize, outBuffer, 0); bufferWriter.Write(outBuffer.AsSpan(0, transed)); hmac.TransformBlock(outBuffer, 0, transed, null, 0); Interlocked.Add(ref _totalSentSize, transed); sequence = sequence.Slice(blockSize); } { int remain = (int)sequence.Length; sequence.CopyTo(inBuffer.AsSpan(0, remain)); var remainBuffer = encryptor.TransformFinalBlock(inBuffer, 0, remain); bufferWriter.Write(remainBuffer); hmac.TransformBlock(remainBuffer, 0, remainBuffer.Length, null, 0); Interlocked.Add(ref _totalSentSize, remainBuffer.Length); } } finally { _bufferPool.GetArrayPool().Return(inBuffer); _bufferPool.GetArrayPool().Return(outBuffer); } } // HMACを書き込む hmac.TransformFinalBlock(Array.Empty <byte>(), 0, 0); bufferWriter.Write(hmac.Hash); } hub.Reader.Complete(); return; } } } catch (OmniSecureConnectionException e) { throw e; } catch (Exception e) { throw new OmniSecureConnectionException(e.Message, e); } throw new OmniSecureConnectionException("Conversion failed."); }
public override int Read(byte[] buffer, int offset, int count) { // Start new block if (_blockMac == null) { _blockMac = _baseStream.ReadExact(32); // To avoid allocations we read into the cache buffer since it's unused at this point and parse from it _baseStream.ReadExact(_buffer, 0, 4); _blockSize = BitConverter.ToInt32(_buffer, 0); // End of stream if (_blockSize == 0) { return(0); } _blockReadPointer = 0; _bufferActualSize = 0; _bufferReadPointer = 0; // Start the MAC calculation for the new block _hmac = new HMACSHA256(Util.ComputeBlockHmacKey(_hmacKey, _blockIndex)); // To avoid allocation we write into the cache buffer and then use it for hashing var forHashing = new OutputSpanStream(_buffer); forHashing.WriteUInt64(_blockIndex); forHashing.WriteInt32(_blockSize); _hmac.TransformBlock(_buffer, 0, forHashing.Position, null, 0); } // Read next piece into the buffer if (_bufferReadPointer >= _bufferActualSize) { var toRead = Math.Min(_buffer.Length, _blockSize - _blockReadPointer); _bufferActualSize = _baseStream.Read(_buffer, 0, toRead); _bufferReadPointer = 0; // Hash the read portion _hmac.TransformBlock(_buffer, 0, _bufferActualSize, null, 0); } var toCopy = Math.Min(count, _bufferActualSize - _bufferReadPointer); Array.Copy(_buffer, _bufferReadPointer, buffer, offset, toCopy); _bufferReadPointer += toCopy; _blockReadPointer += toCopy; // End of block if (_blockReadPointer >= _blockSize) { // Finalize MAC _hmac.TransformFinalBlock(Array.Empty <byte>(), 0, 0); var storedMac = _blockMac; var computedMac = _hmac.Hash; _blockIndex++; _blockMac = null; _hmac.Dispose(); _hmac = null; if (!Crypto.AreEqual(storedMac, computedMac)) { throw new InternalErrorException("Corrupted, block MAC doesn't match"); } } return(toCopy); }
/// <summary> /// Reads one field. /// </summary> /// <returns></returns> private PasswordSafeRecordField ReadField() { var currentBlock = new byte[16]; ReadBytes(currentBlock, "Generic Field"); if (BufferCompare(currentBlock, _eofMarkerBytes)) { return(null); } _decryptor.TransformBlock(currentBlock, 0, currentBlock.Length, currentBlock, 0); if (!BitConverter.IsLittleEndian) { throw new InvalidProgramException("We must be little endian!"); } var fieldLength = BitConverter.ToInt32(currentBlock, 0); if (fieldLength < 0) { throw new InvalidDataException("Invalid field length"); } var type = currentBlock[4]; var dataBuffer = new byte[fieldLength]; // There's a maximum of 11 bytes left of data in the first block. var lengthToCopy = fieldLength > 11 ? 11 : fieldLength; Buffer.BlockCopy(currentBlock, 5, dataBuffer, 0, lengthToCopy); fieldLength -= lengthToCopy; var currentOffset = lengthToCopy; // Now we've handled the first block. Let's see if there's more.... if (fieldLength > 0) { var numberOfBlocks = (fieldLength - 1) / 16 + 1; while (numberOfBlocks-- > 0) { ReadBytes(currentBlock, "Generic Field"); if (BufferCompare(currentBlock, _eofMarkerBytes)) { throw new InvalidDataException("Unexpected end of file marker"); ; } _decryptor.TransformBlock(currentBlock, 0, currentBlock.Length, currentBlock, 0); lengthToCopy = currentBlock.Length > fieldLength ? fieldLength : currentBlock.Length; Buffer.BlockCopy(currentBlock, 0, dataBuffer, currentOffset, lengthToCopy); fieldLength -= lengthToCopy; currentOffset += lengthToCopy; } } var tmpNull = new byte[dataBuffer.Length]; // We only HMAC the actual data - not the length and type. That *SUCKS*!!! _hmac.TransformBlock(dataBuffer, 0, dataBuffer.Length, tmpNull, 0); return(new PasswordSafeRecordField(type, dataBuffer)); }
public void TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { _algo.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); }
/// <summary> /// Returns the SHA256 HMAC of the given <paramref name="prefix"/>, the given <paramref name="request"/>'s /// body, and the given <paramref name="suffix"/> (in that order). /// </summary> /// <param name="request">The current <see cref="HttpRequest"/>.</param> /// <param name="secret">The key data used to initialize the <see cref="HMACSHA256"/>.</param> /// <param name="prefix"> /// If non-<see langword="null"/> and non-empty, additional <c>byte</c>s to include in the hashed content /// before the <paramref name="request"/>'s body. /// </param> /// <param name="suffix"> /// If non-<see langword="null"/> and non-empty, additional <c>byte</c>s to include in the hashed content /// after the <paramref name="request"/>'s body. /// </param> /// <returns> /// A <see cref="Task"/> that on completion provides a <see cref="byte"/> array containing the SHA256 HMAC of /// the <paramref name="prefix"/>, the <paramref name="request"/>'s body, and the <paramref name="suffix"/> /// (in that order). /// </returns> protected virtual async Task <byte[]> ComputeRequestBodySha256HashAsync( HttpRequest request, byte[] secret, byte[] prefix, byte[] suffix) { if (request == null) { throw new ArgumentNullException(nameof(request)); } if (secret == null) { throw new ArgumentNullException(nameof(secret)); } if (secret.Length == 0) { throw new ArgumentException(Resources.General_ArgumentCannotBeNullOrEmpty); } await WebHookHttpRequestUtilities.PrepareRequestBody(request); using (var hasher = new HMACSHA256(secret)) { try { if (prefix != null && prefix.Length > 0) { hasher.TransformBlock( inputBuffer: prefix, inputOffset: 0, inputCount: prefix.Length, outputBuffer: null, outputOffset: 0); } // Split body into 4K chunks. var buffer = new byte[4096]; var inputStream = request.Body; int bytesRead; while ((bytesRead = await inputStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { hasher.TransformBlock( buffer, inputOffset: 0, inputCount: bytesRead, outputBuffer: null, outputOffset: 0); } if (suffix != null && suffix.Length > 0) { hasher.TransformBlock( suffix, inputOffset: 0, inputCount: suffix.Length, outputBuffer: null, outputOffset: 0); } hasher.TransformFinalBlock(Array.Empty <byte>(), inputOffset: 0, inputCount: 0); return(hasher.Hash); } finally { // Reset Position because JsonInputFormatter et cetera always start from current position. request.Body.Seek(0L, SeekOrigin.Begin); } } }
/// <summary> /// Verifies that the signature header matches that of the actual body. /// </summary> protected virtual async Task <bool> VerifySignature(HttpRequestMessage request, string id) { // 1. Ensure configuration for this receiver and id exists. var secretKey = await GetReceiverConfig(request, Name, id, SecretMinLength, SecretMaxLength); // 2. Get the timestamp and expected signatures from the signature header. Header is a comma-separated set // of key=value pairs. var signatureHeaderValue = GetRequestHeader(request, SignatureHeaderName); var pairs = signatureHeaderValue.SplitAndTrim(','); string timestamp = null; var expectedSignatures = new List <string>(); foreach (var pair in pairs) { var keyValuePair = pair.SplitAndTrim('='); if (keyValuePair.Length != 2) { var message = string.Format( CultureInfo.CurrentCulture, StripeReceiverResources.Receiver_InvalidHeaderFormat, SignatureHeaderName); request.GetConfiguration().DependencyResolver.GetLogger().Error(message); var invalidHeader = request.CreateErrorResponse(HttpStatusCode.BadRequest, message); throw new HttpResponseException(invalidHeader); } if (string.Equals(keyValuePair[0], SignatureKey, StringComparison.OrdinalIgnoreCase)) { expectedSignatures.Add(keyValuePair[1]); } else if (string.IsNullOrEmpty(timestamp) && string.Equals(keyValuePair[0], TimestampKey, StringComparison.OrdinalIgnoreCase)) { timestamp = keyValuePair[1]; } } if (string.IsNullOrEmpty(timestamp) || expectedSignatures.Count == 0) { var message = string.Format( CultureInfo.CurrentCulture, StripeReceiverResources.Receiver_HeaderMissingValue, SignatureHeaderName, TimestampKey, SignatureKey); request.GetConfiguration().DependencyResolver.GetLogger().Error(message); var invalidHeader = request.CreateErrorResponse(HttpStatusCode.BadRequest, message); throw new HttpResponseException(invalidHeader); } // 3. Get the actual hash of the timestamp and request body. var secret = Encoding.UTF8.GetBytes(secretKey); var prefix = Encoding.UTF8.GetBytes(timestamp + "."); byte[] actualHash; using (var hasher = new HMACSHA256(secret)) { hasher.TransformBlock( inputBuffer: prefix, inputOffset: 0, inputCount: prefix.Length, outputBuffer: null, outputOffset: 0); var data = await request.Content.ReadAsByteArrayAsync(); actualHash = hasher.ComputeHash(data); } // 4. Verify that the actual hash matches one of the expected hashes. foreach (var expectedSignature in expectedSignatures) { // While this looks repetitious compared to hex-encoding actualHash (once), a single v1 entry in the // header is the normal case. Expect multiple signatures only when rolling secret keys. byte[] expectedHash; try { expectedHash = EncodingUtilities.FromHex(expectedSignature); } catch (Exception ex) { var message = string.Format( CultureInfo.CurrentCulture, StripeReceiverResources.Receiver_BadSignatureEncoding, SignatureHeaderName, SignatureKey); request.GetConfiguration().DependencyResolver.GetLogger().Error(message, ex); var invalidEncoding = request.CreateErrorResponse(HttpStatusCode.BadRequest, message); throw new HttpResponseException(invalidEncoding); } if (SecretEqual(expectedHash, actualHash)) { return(true); } } return(false); }
/// <summary> /// Encryption Algorithm /// cell_iv = HMAC_SHA-2-256(iv_key, cell_data) truncated to 128 bits /// cell_ciphertext = AES-CBC-256(enc_key, cell_iv, cell_data) with PKCS7 padding. /// (optional) cell_tag = HMAC_SHA-2-256(mac_key, versionbyte + cell_iv + cell_ciphertext + versionbyte_length) /// cell_blob = versionbyte + [cell_tag] + cell_iv + cell_ciphertext /// </summary> /// <param name="plainText">Plaintext data to be encrypted</param> /// <param name="hasAuthenticationTag">Does the algorithm require authentication tag.</param> /// <returns>Returns the ciphertext corresponding to the plaintext.</returns> protected byte[] EncryptData(byte[] plainText, bool hasAuthenticationTag) { // Empty values get encrypted and decrypted properly for both Deterministic and Randomized encryptions. Debug.Assert(plainText != null); byte[] iv = new byte[BlockSizeInBytes]; // Prepare IV // Should be 1 single block (16 bytes) if (this.isDeterministic) { SecurityUtility.GetHMACWithSHA256(plainText, this.dataEncryptionKey.IVKey, iv); } else { SecurityUtility.GenerateRandomBytes(iv); } int numBlocks = (plainText.Length / BlockSizeInBytes) + 1; // Final blob we return = version + HMAC + iv + cipherText const int hmacStartIndex = 1; int authenticationTagLen = hasAuthenticationTag ? KeySizeInBytes : 0; int ivStartIndex = hmacStartIndex + authenticationTagLen; int cipherStartIndex = ivStartIndex + BlockSizeInBytes; // this is where hmac starts. // Output buffer size = size of VersionByte + Authentication Tag + IV + cipher Text blocks. int outputBufSize = sizeof(byte) + authenticationTagLen + iv.Length + (numBlocks * BlockSizeInBytes); byte[] outBuffer = new byte[outputBufSize]; // Store the version and IV rightaway outBuffer[0] = this.algorithmVersion; Buffer.BlockCopy(iv, 0, outBuffer, ivStartIndex, iv.Length); AesCryptoServiceProvider aesAlg; // Try to get a provider from the pool. // If no provider is available, create a new one. if (!this.cryptoProviderPool.TryDequeue(out aesAlg)) { aesAlg = new AesCryptoServiceProvider(); try { // Set various algorithm properties aesAlg.Key = this.dataEncryptionKey.EncryptionKey; aesAlg.Mode = cipherMode; aesAlg.Padding = paddingMode; } catch (Exception) { if (aesAlg != null) { aesAlg.Dispose(); } throw; } } try { // Always set the IV since it changes from cell to cell. aesAlg.IV = iv; // Compute CipherText and authentication tag in a single pass using (ICryptoTransform encryptor = aesAlg.CreateEncryptor()) { Debug.Assert(encryptor.CanTransformMultipleBlocks, "AES Encryptor can transform multiple blocks"); int count = 0; int cipherIndex = cipherStartIndex; // this is where cipherText starts if (numBlocks > 1) { count = (numBlocks - 1) * BlockSizeInBytes; cipherIndex += encryptor.TransformBlock(plainText, 0, count, outBuffer, cipherIndex); } byte[] buffTmp = encryptor.TransformFinalBlock(plainText, count, plainText.Length - count); // done encrypting Buffer.BlockCopy(buffTmp, 0, outBuffer, cipherIndex, buffTmp.Length); cipherIndex += buffTmp.Length; } if (hasAuthenticationTag) { using (HMACSHA256 hmac = new HMACSHA256(this.dataEncryptionKey.MACKey)) { Debug.Assert(hmac.CanTransformMultipleBlocks, "HMAC can't transform multiple blocks"); hmac.TransformBlock(version, 0, version.Length, version, 0); hmac.TransformBlock(iv, 0, iv.Length, iv, 0); // Compute HMAC on final block hmac.TransformBlock(outBuffer, cipherStartIndex, numBlocks * BlockSizeInBytes, outBuffer, cipherStartIndex); hmac.TransformFinalBlock(versionSize, 0, versionSize.Length); byte[] hash = hmac.Hash; Debug.Assert(hash.Length >= authenticationTagLen, "Unexpected hash size"); Buffer.BlockCopy(hash, 0, outBuffer, hmacStartIndex, authenticationTagLen); } } } finally { // Return the provider to the pool. this.cryptoProviderPool.Enqueue(aesAlg); } return(outBuffer); }
/// <summary> /// Loads data from a file. /// If both passphrase and key are present, passphrase takes precedence. /// </summary> /// <param name="stream">Stream.</param> /// <param name="passphraseBuffer">Password bytes. Caller has to avoid keeping bytes unencrypted in memory.</param> /// <param name="keyBuffer">Key bytes containing both key K and L. Must be 64 bytes. Caller has to avoid keeping bytes unencrypted in memory.</param> /// <exception cref="ArgumentNullException">Stream cannot be null. -or- Passphrase cannot be null.</exception> /// <exception cref="ArgumentOutOfRangeException">Keys must be 64 bytes long.</exception> /// <exception cref="FormatException">Unrecognized file format. -or- Password mismatch. -or- Authentication mismatch.</exception> internal static Document InternalLoad(Stream stream, byte[]?passphraseBuffer, byte[]?keyBuffer) { if ((passphraseBuffer == null) && (keyBuffer == null)) { throw new ArgumentNullException(nameof(passphraseBuffer), "Passphrase cannot be null."); } if ((passphraseBuffer == null) && (keyBuffer != null) && (keyBuffer.Length != 64)) { throw new ArgumentOutOfRangeException(nameof(keyBuffer), "Keys must be 64 bytes long."); } var buffer = new byte[16384]; using (var ms = new MemoryStream()) { int read; while ((read = stream.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, read); } buffer = ms.ToArray(); } if ((buffer.Length < 200) || (BitConverter.ToInt32(buffer, 0) != Tag) || (BitConverter.ToInt32(buffer, buffer.Length - 32 - 16) != Tag) || (BitConverter.ToInt32(buffer, buffer.Length - 32 - 12) != TagEof) || (BitConverter.ToInt32(buffer, buffer.Length - 32 - 8) != Tag) || (BitConverter.ToInt32(buffer, buffer.Length - 32 - 4) != TagEof)) { throw new FormatException("Unrecognized file format."); } var salt = new byte[32]; Buffer.BlockCopy(buffer, 4, salt, 0, salt.Length); var iter = BitConverter.ToUInt32(buffer, 36); byte[]? stretchedKey = null, keyK = null, keyL = null, data = null; try { if (passphraseBuffer != null) { stretchedKey = GetStretchedKey(passphraseBuffer, salt, iter); if (!AreBytesTheSame(GetSha256Hash(stretchedKey), buffer, 40)) { throw new CryptographicException("Password mismatch."); } keyK = DecryptKey(stretchedKey, buffer, 72); keyL = DecryptKey(stretchedKey, buffer, 104); } else if (keyBuffer != null) { keyK = new byte[32]; keyL = new byte[32]; Buffer.BlockCopy(keyBuffer, 0, keyK, 0, keyK.Length); Buffer.BlockCopy(keyBuffer, 32, keyL, 0, keyL.Length); } else { throw new InvalidOperationException("No passphrase or key buffer."); } var iv = new byte[16]; Buffer.BlockCopy(buffer, 136, iv, 0, iv.Length); data = DecryptData(keyK, iv, buffer, 152, buffer.Length - 200); using var dataHash = new HMACSHA256(keyL); var dataOffset = 0; var headerFields = new List <Header>(); while (dataOffset < data.Length) { var fieldLength = BitConverter.ToInt32(data, dataOffset + 0); var fieldLengthFull = ((fieldLength + 5 - 1) / 16 + 1) * 16; var fieldType = (HeaderType)data[dataOffset + 4]; var fieldData = new byte[fieldLength]; try { Buffer.BlockCopy(data, dataOffset + 5, fieldData, 0, fieldLength); dataOffset += fieldLengthFull; //there is ALWAYS some random bytes added, thus extra block if 16 bytes dataHash.TransformBlock(fieldData, 0, fieldData.Length, null, 0); //not hashing length nor type - wtf? if (fieldType == HeaderType.EndOfEntry) { break; } headerFields.Add(new Header(fieldType, fieldData)); } finally { Array.Clear(fieldData, 0, fieldData.Length); } } if ((headerFields.Count == 0) || (headerFields[0].Version < 0x0300)) { throw new FormatException("Unrecognized file format version."); } var recordFields = new List <List <Record> >(); List <Record>?records = null; while (dataOffset < data.Length) { var fieldLength = BitConverter.ToInt32(data, dataOffset + 0); var fieldLengthFull = ((fieldLength + 5 - 1) / 16 + 1) * 16; var fieldType = (RecordType)data[dataOffset + 4]; var fieldData = new byte[fieldLength]; try { Buffer.BlockCopy(data, dataOffset + 5, fieldData, 0, fieldLength); dataOffset += fieldLengthFull; //there is ALWAYS some random bytes added, thus extra block if 16 bytes dataHash.TransformBlock(fieldData, 0, fieldData.Length, null, 0); //not hashing length nor type - wtf? if (fieldType == RecordType.EndOfEntry) { records = null; continue; } if (records == null) { records = new List <Record>(); recordFields.Add(records); } records.Add(new Record(fieldType, fieldData)); } finally { Array.Clear(fieldData, 0, fieldData.Length); } } dataHash.TransformFinalBlock(Array.Empty <byte>(), 0, 0); if (!AreBytesTheSame(dataHash.Hash, buffer, buffer.Length - 32)) { throw new CryptographicException("Authentication mismatch."); } return(new Document(passphraseBuffer, (int)iter, headerFields, recordFields.ToArray())); } catch (CryptographicException ex) { throw new FormatException(ex.Message, ex); } finally { //best effort to sanitize memory if (stretchedKey != null) { Array.Clear(stretchedKey, 0, stretchedKey.Length); } if (keyK != null) { Array.Clear(keyK, 0, keyK.Length); } if (keyL != null) { Array.Clear(keyL, 0, keyL.Length); } if (data != null) { Array.Clear(data, 0, data.Length); } if (buffer != null) { Array.Clear(buffer, 0, buffer.Length); } } }