/// <summary> /// Decrypt an encrypted packet of data /// </summary> /// <param name="encryptedPacket">Packet containing data</param> /// <param name="publicKey">Public RSA key of sender</param> /// <param name="skipSignature"></param> /// <exception cref="CryptoException"></exception> /// <returns>Decrypted data of packet</returns> public static byte[] Decrypt(EncryptedPacket encryptedPacket, RSAParameters publicKey, bool skipSignature = false) { // decrypt AES session key with private RSA key byte[] sessionKey; try { sessionKey = AsymmetricEncryption.Decrypt(encryptedPacket.EncryptedSessionKey); } catch (CryptographicException e) { throw new CryptoException("Error while decryption AES session key", e); } // rehash data with session key byte[] hashedData; try { hashedData = Hashing.HmacSha(encryptedPacket.EncryptedData, sessionKey); } catch (CryptographicException e) { throw new CryptoException("Error while hashing data", e); } // check hash bool checkedHash = Hashing.CompareHashes(hashedData, encryptedPacket.Hmac); if (!checkedHash) { throw new CryptoException("Hash validation failed, data may have been modified!"); } // check signature if required if (!skipSignature) { bool checkedSignature; try { checkedSignature = AsymmetricEncryption.CheckSignature(encryptedPacket.Signature, publicKey, encryptedPacket.Hmac); } catch (CryptographicException e) { throw new CryptoException("Error while checking signature", e); } if (!checkedSignature) { throw new CryptoException("Signature check failed, packet may have come from a different sender."); } } // decrypt data with AES key and IV try { return(SymmetricEncryption.Decrypt(encryptedPacket.EncryptedData, sessionKey, encryptedPacket.Iv)); } catch (CryptographicException e) { throw new CryptoException("Error while decrypting data", e); } }
/// <summary> /// Decrypt a file and write it to another file /// </summary> /// <param name="inputStream">File to read encrypted packet from</param> /// <param name="outputStream">File to write decrypted data to</param> /// <param name="publicKey">Public key of sender</param> public static async Task <bool> DecryptFile(Stream inputStream, Stream outputStream, RSAParameters publicKey) { // roll back stream to start inputStream.Position = 0; // read data type inputStream.ReadByte(); // read and decrypt aes key byte[] encryptedAesKeyLengthBuffer = new byte[2]; await inputStream.ReadAsync(encryptedAesKeyLengthBuffer, 0, 2); await inputStream.FlushAsync(); ushort encryptedAesKeyLength = BitConverter.ToUInt16(encryptedAesKeyLengthBuffer, 0); byte[] encryptedAesKey = new byte[encryptedAesKeyLength]; await inputStream.ReadAsync(encryptedAesKey, 0, encryptedAesKeyLength); await inputStream.FlushAsync(); byte[] aesKey = AsymmetricEncryption.Decrypt(encryptedAesKey); // read aes iv byte[] iv = new byte[16]; await inputStream.ReadAsync(iv, 0, 16); await inputStream.FlushAsync(); // read hash byte[] hmac = new byte[64]; await inputStream.ReadAsync(hmac, 0, 64); await inputStream.FlushAsync(); // read signature int signatureLength = AsymmetricEncryption.PublicKey.Modulus.Length; byte[] signature = new byte[signatureLength]; await inputStream.ReadAsync(signature, 0, signatureLength); await inputStream.FlushAsync(); // check signature if (!AsymmetricEncryption.CheckSignature(signature, publicKey, hmac)) { throw new CryptoException("Signature check failed, file could have been sent by somebody else!"); } try { // create streamers using (HashStreamer hashStreamer = new HashStreamer(aesKey)) using (SymmetricStreamer symmetricStreamer = new SymmetricStreamer(aesKey, iv)) { long currentPos = inputStream.Position; // create streams var hmacStream = hashStreamer.HmacShaStream(new MemoryStream(), aesKey, CryptoStreamMode.Write); var decryptStream = symmetricStreamer.DecryptStream(outputStream, CryptoStreamMode.Write); // create hash await inputStream.CopyToAsync(hmacStream); inputStream.Position = currentPos; await inputStream.FlushAsync(); // skip decrypting if the hash isn't correct if (!Hashing.CompareHashes(hashStreamer.Hash, hmac)) { return(false); } // decrypt the actual data await inputStream.CopyToAsync(decryptStream); await inputStream.FlushAsync(); // Something something, absolute bullshit inputStream.Position = inputStream.Seek(-16, SeekOrigin.End); await inputStream.CopyToAsync(decryptStream); // flush it all await outputStream.FlushAsync(); return(true); } } catch (CryptographicException e) { throw new CryptoException("Error while decrypting stream", e); } }