open System
open System.IO
-// To read and write metadata.
+/// To read and write metadata.
type internal Metadata (d: (string * string) list) =
- // Read metadata from a stream.
+ /// Read metadata from a stream.
new (stream : Stream) =
let reader = new BinaryReader (stream)
let length = reader.ReadByte () |> int
- Metadata ([for _ in 1..length -> reader.ReadString (), reader.ReadString ()])
+ Metadata ([for _ in 1 .. length -> reader.ReadString (), reader.ReadString ()])
- // Write metadata to a stream.
+ /// Write metadata to a stream.
member this.WriteTo (stream : Stream) =
let writer = new BinaryWriter (stream)
writer.Write (byte d.Length)
List.iter (fun (key : string, value : string) -> writer.Write key; writer.Write value) d
- // May raise 'KeyNotFoundException'.
+ /// May raise 'KeyNotFoundException'.
member this.get (key: string) : string =
List.pick (function
| (k, v) when k = key -> Some (v)
let generatKeysPair () : Key * Key = Crypto.generateRSAKeysPair ()
- // Format of the container:
- // <mac><signature><encrypted keys><cyphertext>
- // Where the sizes of the three first parts are given by 'hmacSize', 'signatureSize' and 'keysSize'.
+ /// Format of the container:
+ /// <mac><signature><encrypted keys><cyphertext>
+ /// Where the sizes of the three first parts are given by 'hmacSize', 'signatureSize' and 'keysSize'.
let encryptFile (inputFilePath : string) (outputFilePath : string) (signaturePrivKey: Key) (cryptPubKey : Key) =
let keyAES, keyMAC, iv = Crypto.rand 16, Crypto.rand 32, Crypto.rand 16
let fileInfo = FileInfo (inputFilePath)
// Write the signature.
Crypto.signRSA signaturePrivKey hmac.Hash |> writer.Write
- // May raise one of the following error:
- // * IntegrityError
- // * SignatureMismatch
- // * UnableToDecryptAESKeys
+ /// May raise one of the following error:
+ /// * IntegrityError
+ /// * SignatureMismatch
+ /// * UnableToDecryptAESKeys
let decryptFile (sourceFilePath : string) (targetDirPath : string) (signaturePubKey: Key) (decryptPrivKey : Key) =
use inputStream = new FileStream (sourceFilePath, FileMode.Open, FileAccess.Read)
use reader = new BinaryReader (inputStream)
try reader.ReadBytes keysSize |> Crypto.decryptRSA decryptPrivKey
with
| :? Security.Cryptography.CryptographicException -> raise UnableToDecryptKeys
- let keyAES = keys.[0..15]
- let keyMAC = keys.[16..47]
- let iv = keys.[48..63]
+ let keyAES = keys.[0 .. 15]
+ let keyMAC = keys.[16 .. 47]
+ let iv = keys.[48 .. 63]
// Integrity validation.
let mac' = Crypto.ComputeHMAC keyMAC inputStream
use aes = new AesCryptoServiceProvider (KeySize = aesKeySize)
new CryptoStream (inputStream, aes.CreateDecryptor (key, iv), CryptoStreamMode.Read)
- // Create a stream to compute the HMAC-SHA256 against all data being written.
+ /// Create a stream to compute HMAC-SHA256 against all data being written.
let HMACStream (key: byte[]) (outputStream: Stream) : Stream * HMACSHA256 =
if key.Length <> 32 then raise KeySizeError
let hmac = new HMACSHA256 (key)
new CryptoStream (outputStream, hmac, CryptoStreamMode.Write) :> Stream, hmac
+ /// Compute HMAC-SHA256 for all the data in the input stream.
let ComputeHMAC (key: byte[]) (inputStream: Stream) : byte[] =
if key.Length <> 32 then raise KeySizeError
use hmac = new HMACSHA256 (key)
decrypt ()
assert (File.ReadAllText plainFilename = fileContent)
- printfn "== Altering the MAC..."
+ printfn "== Altering the MAC... (%d bytes)" (API.hmacSize - 1)
for i in 0 .. API.hmacSize - 1 do
printf "."
encrypt ()
| error -> assert (error :? IntegrityError)
printfn ""
- printfn "== Altering the signature..."
+ printfn "== Altering the signature... (%d bytes)" (API.signatureSize - 1)
for i in 0 .. API.signatureSize - 1 do
printf "."
encrypt ()
| error -> assert (error :? SignatureMismatch)
printfn ""
- printfn "== Altering the keys..."
+ printfn "== Altering the keys... (%d bytes)" (API.keysSize - 1)
for i in 0 .. API.keysSize - 1 do
printf "."
encrypt ()
| error -> assert (error :? UnableToDecryptKeys)
printfn ""
- printfn "== Altering the cyphertext..."
- encrypt ()
- incrementByteCipherFileAt (int64 <| API.hmacSize + API.signatureSize + API.keysSize)
- try
- decrypt ()
- assert false
- with
- | error -> assert (error :? IntegrityError)
+ let cyphertextLength = (int (FileInfo (cipherFilename)).Length) + API.hmacSize + API.signatureSize + API.keysSize
+ printfn "== Altering the cyphertext... (%d bytes)" cyphertextLength
+ for i in 0 .. cyphertextLength do
+ printf "."
+ encrypt ()
+ incrementByteCipherFileAt (int64 <| API.hmacSize + API.signatureSize + API.keysSize + i)
+ try
+ decrypt ()
+ assert false
+ with
+ | error -> assert (error :? IntegrityError)
+ printfn ""
File.Delete cipherFilename
File.Delete plainFilename
\subsection{Quel est le niveau de sécurité que l'on souhaite atteindre ?}
-Le niveau souhaité est de 128 bits. Cela implique l'utilisation d'une clef \emph{AES} de 128 bits et de clefs \emph{RSA} de 3072 bits d'après~\cite{wiki-key-size}.
+Le niveau souhaité est de 128 bits. Cela implique l'utilisation d'une clef \emph{AES} de 128 bits et de clefs \emph{RSA} de 3072 bits d'après \emph{Wikipedia}~\cite{wiki-key-size}.
Les éléments de sécurité suivants sont requis :
\item \emph{AES-CBC128} pour le chiffrement symétrique du contenu du fichier et des méta-données associées. Le bourrage \emph{PKCS7} est utilisé.
\end{itemize}
-D'après~\cite{wiki-key-size}, la société \emph{RSA Security}\footnote{\rsasecurity} annonce qu'une taille de clefs \emph{RSA} de 3072 bits est suffisante pour une utilisation au delà de 2030. Cela dépend également du niveau d'importance des documents que l'on souhaite chiffrer dans la mesure ou une attaque demande énormément de moyens.
+D'après \emph{Wikipedia}~\cite{wiki-key-size}, la société \emph{RSA Security}\footnote{\rsasecurity} annonce qu'une taille de clefs \emph{RSA} de 3072 bits est suffisante pour une utilisation au delà de 2030. Cela dépend également du niveau d'importance des documents que l'on souhaite chiffrer dans la mesure où une attaque demande énormément de moyens.
-Toujours d'après~\cite{wiki-key-size}, une taille de clef \emph{AES} de 128 bits reste, actuellement, hors de portée de toutes attaques.
+Toujours d'après \emph{Wikipedia}~\cite{wiki-key-size}, une taille de clef \emph{AES} de 128 bits reste, actuellement, hors de portée de toutes attaques.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Le type \texttt{vint} correspond à un entier de taille variable, initialement occupant un octet.
-Comme les clefs (\emph{AES} et \emph{HMAC-SHA256}) sont différentes à chaque chiffrement, que le \emph{MAC} dépend de sa clef et des données chiffrées et que la signature dépend du \emph{MAC} alors l'ensemble des octets des différentes parties du fichier résultat va être fortement différent d'un chiffrement à l'autre pour le même fichier en entrée.
+Comme les clefs (\emph{AES} et \emph{HMAC-SHA256}) sont différentes à chaque chiffrement, que le \emph{MAC} dépend de sa clef et des données chiffrées et que la signature dépend du \emph{MAC}, alors l'ensemble des octets des différentes parties du fichier résultat va être fortement différent d'un chiffrement à l'autre pour le même fichier en entrée.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Il est possible de compiler la solution à l'aide de \emph{MonoDevelop}\footnote{\monodevelop} ou de \emph{Visual Studio 2012}. Le script \emph{Bash} \texttt{labo2-fsharp/run\_tests.sh} permet de compiler la solution puis d'exécuter un certain nombre de tests.
-À partir du dossier \texttt{labo2-fsharp} et après avoir compiler en \emph{release} la solution, voici ce qu'il est possible d'effectuer :
+À partir du dossier \texttt{labo2-fsharp} et après avoir compilé en \emph{release} la solution, voici ce qu'il est possible d'effectuer :
\begin{itemize}
\item \texttt{CryptoFileTests/bin/Release/CryptoFileTests.exe tests} : Réalise une série de tests.
\subsection{Mesures de performance}
-Quelques mesures sur un fichier de 871 MiB ont été effectuées sous \emph{Linux} avec \emph{Mono} 3.10.0 ainsi que sous \emph{Windows 8.1} avec \emph{Visual Studio 2012}. Il est a noter que l'implémentation \emph{AES} de \emph{Mono} est en \emph{C\#} et n'utilise évidemment pas l’accélération matérielle d'\emph{Intel} présente sur la machine : \emph{AES-NI}.
+Quelques mesures sur un fichier de 871 MiB ont été effectuées sous \emph{Linux} avec \emph{Mono} 3.10.0 ainsi que sous \emph{Windows 8.1} avec \emph{Visual Studio 2012}. Il est à noter que l'implémentation \emph{AES} de \emph{Mono} est en \emph{C\#} et n'utilise évidemment pas l’accélération matérielle d'\emph{Intel} présente sur la machine : \emph{AES-NI}.
-Les tests sous \emph{Windows 8} ont été fait sur une machine ne possédant pas \emph{AES-NI}. Cet ensemble d'instructions est normalement supporté par l’implémentation du \emph{runtime} \emph{.NET} de \emph{Microsoft}.
+Les tests sous \emph{Windows 8} ont été fais sur une machine ne possédant pas \emph{AES-NI}. Cet ensemble d'instructions est normalement supporté par l’implémentation du \emph{runtime} \emph{.NET} de \emph{Microsoft}.
\begin{tabular}{ l | r | r | r | r }
& \multicolumn{2}{c|}{Chiffrement} & \multicolumn{2}{|c}{Déchiffrement} \\
\section{Analyse de la sécurité de l'implémentation}
-\subsection{Quelles sont les parties critiques du code et comment s'assure-t-on que ces parties soient correctement implémentées ?}
+\subsection{Quelles sont les parties critiques du code et comment s'assure-t-on que ces parties sont correctement implémentées ?}
Le choix des algorithmes, de leurs paramètres et de leur implémentation est une partie critique. Il est possible de se référer aux recommandations de certains organismes comme par exemple le \emph{NIST}\footnote{\emph{National Institute of Standards and Technology}}.