namespace CryptoFile open System.IO type internal Metadata (d: (string * string) list) = new (stream : Stream, size: int) = let binaryReader = new BinaryReader (stream) new Metadata ([]) member this.WriteTo (stream : Stream) = let memoryStream = new MemoryStream () // To know the serialized meta-data size before writtent them to 'stream'. let memoryWriter = new BinaryWriter (memoryStream) List.iter (fun (key : string, value : string) -> memoryWriter.Write key; memoryWriter.Write value) d (new BinaryWriter (stream)).Write (int memoryStream.Length) memoryStream.CopyTo (stream) module API = module internal MetaData = let filename = "filename" let creationTimeKey = "file-creation-time" let generatKeysPair : Key * Key = Crypto.generateRSAKeysPair // Encrypt a given file let encryptFile (inputFilePath : string) (outputFilePath : string) (signaturePrivKey: Key) (cryptPubKey : Key) = let keyAES, keyMAC, iv = Crypto.rand 32, Crypto.rand 32, Crypto.rand 16 let fileInfo = new FileInfo (inputFilePath) use inputStream = new FileStream (inputFilePath, FileMode.Open, FileAccess.Read) use outputStream = new FileStream (outputFilePath, FileMode.Create, FileAccess.Write) let writer = new BinaryWriter (outputStream) writer.Seek (32 + 256, SeekOrigin.Current) |> ignore // Skips mac and signature. They will be written later. Crypto.encryptRSA cryptPubKey (Array.append keyAES <| Array.append keyMAC iv) |> writer.Write let (hmacStream, hmac) = Crypto.HMACStream keyMAC outputStream use cryptoStream = Crypto.encryptAES keyAES iv hmacStream let cryptoWriter = new BinaryWriter (cryptoStream) // Write the file metadata. let metaData = new Metadata ([MetaData.filename, fileInfo.Name MetaData.creationTimeKey, fileInfo.CreationTimeUtc.Ticks.ToString ()]) metaData.WriteTo cryptoStream // Write the content of the file. inputStream.CopyTo cryptoStream cryptoStream.FlushFinalBlock () // Write the HMAC at the begining of the file. outputStream.Position <- 0L writer.Write hmac.Hash // Write the signature. Crypto.signRSA signaturePrivKey hmac.Hash |> writer.Write () let decryptFile (sourceFilePath : string) (targetDirPath : string) (signaturePubKey: Key) (decryptPrivKey : Key) = ()