From 61a8b3492e89e883b23c158eb52ba2b070234df8 Mon Sep 17 00:00:00 2001 From: Ummon Date: Sat, 29 Nov 2014 09:35:08 +0100 Subject: [PATCH] Add some tests. --- labo2-fsharp/CryptoFile/API.fs | 9 +- labo2-fsharp/CryptoFile/CryptoFile.fsproj | 8 +- labo2-fsharp/CryptoFile/Types.fs | 1 + .../CryptoFile/{Tests.fs => UnitTests.fs} | 22 +++- .../CryptoFileTests/CryptoFileTests.fsproj | 108 +++++++++--------- labo2-fsharp/CryptoFileTests/Program.fs | 10 +- labo2-fsharp/CryptoFileTests/Tests.fs | 75 ++++++++++++ labo2-fsharp/labo2-fsharp.userprefs | 20 ++-- labo2-fsharp/run_tests.sh | 10 +- rapport/main.tex | 20 ++-- 10 files changed, 195 insertions(+), 88 deletions(-) rename labo2-fsharp/CryptoFile/{Tests.fs => UnitTests.fs} (70%) create mode 100644 labo2-fsharp/CryptoFileTests/Tests.fs diff --git a/labo2-fsharp/CryptoFile/API.fs b/labo2-fsharp/CryptoFile/API.fs index 1601c97..250bdbe 100644 --- a/labo2-fsharp/CryptoFile/API.fs +++ b/labo2-fsharp/CryptoFile/API.fs @@ -42,7 +42,7 @@ module API = Crypto.encryptRSA cryptPubKey (Array.append keyAES <| Array.append keyMAC iv) |> writer.Write // Plaintext -> cryptoStream -> hmacStream -> cyphertext. - let (hmacStream, hmac) = Crypto.HMACStream keyMAC outputStream + let hmacStream, hmac = Crypto.HMACStream keyMAC outputStream use cryptoStream = Crypto.encryptAES keyAES iv hmacStream let cryptoWriter = new BinaryWriter (cryptoStream) @@ -67,7 +67,10 @@ module API = use reader = new BinaryReader (inputStream) let mac = reader.ReadBytes 32 let signature = reader.ReadBytes 256 - let keys = reader.ReadBytes 256 |> Crypto.decryptRSA decryptPrivKey + let keys = + try reader.ReadBytes 256 |> Crypto.decryptRSA decryptPrivKey + with + | :? Security.Cryptography.CryptographicException -> raise UnableToDecryptAESKeys let keyAES = keys.[0..31] let keyMAC = keys.[32..63] let iv = keys.[64..79] @@ -76,7 +79,7 @@ module API = let mac' = Crypto.ComputeHMAC keyMAC inputStream if mac' <> mac then raise IntegrityError - + // Authentication validation. if not <| Crypto.verifySignRSA signaturePubKey mac' signature then raise SignatureMismatch diff --git a/labo2-fsharp/CryptoFile/CryptoFile.fsproj b/labo2-fsharp/CryptoFile/CryptoFile.fsproj index 0e0ea35..cf20e54 100644 --- a/labo2-fsharp/CryptoFile/CryptoFile.fsproj +++ b/labo2-fsharp/CryptoFile/CryptoFile.fsproj @@ -19,12 +19,6 @@ true false false - - - - - - tests true @@ -50,8 +44,8 @@ - + \ No newline at end of file diff --git a/labo2-fsharp/CryptoFile/Types.fs b/labo2-fsharp/CryptoFile/Types.fs index 38457be..7520663 100644 --- a/labo2-fsharp/CryptoFile/Types.fs +++ b/labo2-fsharp/CryptoFile/Types.fs @@ -4,3 +4,4 @@ type Key = string // For public and private RSA keys. exception IntegrityError exception SignatureMismatch +exception UnableToDecryptAESKeys diff --git a/labo2-fsharp/CryptoFile/Tests.fs b/labo2-fsharp/CryptoFile/UnitTests.fs similarity index 70% rename from labo2-fsharp/CryptoFile/Tests.fs rename to labo2-fsharp/CryptoFile/UnitTests.fs index e1f933b..fb46eb7 100644 --- a/labo2-fsharp/CryptoFile/Tests.fs +++ b/labo2-fsharp/CryptoFile/UnitTests.fs @@ -1,19 +1,24 @@ namespace CryptoFile -module Tests = +module UnitTests = + open System.IO open System.Text open System.Security.Cryptography open Crypto let testRSA () = let kpub, kpriv = generateRSAKeysPair + let plaintext = "Hello, World!" printfn "plaintext: %A" plaintext + let cipherdata = encryptRSA kpub (Encoding.UTF8.GetBytes plaintext) printfn "cipherdata: (size: %A) %A" cipherdata.Length cipherdata + let decryptedData = decryptRSA kpriv cipherdata let decryptedText = Encoding.UTF8.GetString decryptedData printfn "decryptedtext: %A" decryptedText + assert (plaintext = decryptedText) printfn "testRSA OK" @@ -26,6 +31,19 @@ module Tests = assert not (verifySignRSA kpub (sha256.ComputeHash (Encoding.UTF8.GetBytes "Hello!")) signature) printfn "testRSASignature OK" - let runAllTests () = + let testAES () = + let plaintext = "There is no place like 127.0.0.1" + let output = new MemoryStream () + let sr = new StreamReader (output) + let key = Crypto.rand 32 + let iv = Crypto.rand 16 + + let input = encryptAES key iv output + let sw = new StreamWriter (input) + + sw.Write plaintext + assert (sr.ReadToEnd () = plaintext) + + let runAllUnitTests () = testRSA () testRSASignature () \ No newline at end of file diff --git a/labo2-fsharp/CryptoFileTests/CryptoFileTests.fsproj b/labo2-fsharp/CryptoFileTests/CryptoFileTests.fsproj index 2f24211..ea531a3 100644 --- a/labo2-fsharp/CryptoFileTests/CryptoFileTests.fsproj +++ b/labo2-fsharp/CryptoFileTests/CryptoFileTests.fsproj @@ -1,52 +1,58 @@ - - - - Debug - x86 - {FA5B9C91-036B-455C-892B-05A7FC398158} - Exe - CryptoFileTests - CryptoFileTests - v4.5 - - - true - full - false - bin\Debug - DEBUG - prompt - true - false - x86 - tests - - - false - none - true - bin\Release - prompt - x86 - true - true - - - - - - - - - - - - - - - - {CDB168EA-04F9-4A8B-A3B4-27D9A6390269} - CryptoFile - - + + + + Debug + x86 + {FA5B9C91-036B-455C-892B-05A7FC398158} + Exe + CryptoFileTests + CryptoFileTests + v4.5 + + + true + full + false + bin\Debug + DEBUG + prompt + true + false + x86 + tests + + + + + + + + false + none + true + bin\Release + prompt + x86 + true + true + + + + + + + + + + + + + + + + + {CDB168EA-04F9-4A8B-A3B4-27D9A6390269} + CryptoFile + + \ No newline at end of file diff --git a/labo2-fsharp/CryptoFileTests/Program.fs b/labo2-fsharp/CryptoFileTests/Program.fs index b824912..a0cfba9 100644 --- a/labo2-fsharp/CryptoFileTests/Program.fs +++ b/labo2-fsharp/CryptoFileTests/Program.fs @@ -24,10 +24,10 @@ module internal Keys = | _ -> use swPub = new StreamWriter (filenamePub) use swPriv = new StreamWriter (filenamePriv) - let keySigPub, keySigPriv = API.generatKeysPair - swPub.Write keySigPub - swPriv.Write keySigPriv - keySigPub, keySigPriv + let keyPub, keyPriv = API.generatKeysPair + swPub.Write keyPub + swPriv.Write keyPriv + keyPub, keyPriv let getSig : Key * Key = getKey "keys-sign.pub" "keys-sign.priv" let getCrypt : Key * Key = getKey "keys-crypt.pub" "keys-crypt.priv" @@ -38,7 +38,7 @@ let main args = let keyCryptPub, keyCryptPriv = Keys.getCrypt match args with - | [| "tests" |] -> Tests.runAllTests () + | [| "tests" |] -> Tests.doSomeTests () | [| "encrypt"; input; output |] -> API.encryptFile input output keySigPriv keyCryptPub | [| "decrypt"; input; outputDir |] -> API.decryptFile input outputDir keySigPub keyCryptPriv | _ -> printUsage () diff --git a/labo2-fsharp/CryptoFileTests/Tests.fs b/labo2-fsharp/CryptoFileTests/Tests.fs new file mode 100644 index 0000000..dd1b3e0 --- /dev/null +++ b/labo2-fsharp/CryptoFileTests/Tests.fs @@ -0,0 +1,75 @@ +module CryptoFileTests.Tests + +open System.IO +open CryptoFile + +let doSomeTests () = + printfn "===== Unit tests" + CryptoFile.UnitTests.runAllUnitTests () + printfn "===== Unit tests OK" + + printfn "===== API tests" + let plainFilename = "test.txt" + let cipherFilename = "test.cipher" + let fileContent = "Screw the NSA" + + File.WriteAllText (plainFilename, fileContent) + + let keyCryptPub, keyCryptPriv = API.generatKeysPair + let keySigPub, keySigPriv = API.generatKeysPair + + let encrypt () = + API.encryptFile plainFilename cipherFilename keySigPriv keyCryptPub + + let decrypt () = + API.decryptFile cipherFilename "." keySigPub keyCryptPriv + + let writeByteToCipherFileAt byte position = + using (new FileStream (cipherFilename, FileMode.Open, FileAccess.Write)) + (fun fs -> fs.Position <- position + fs.Write ([| byte |], 0, 1)) + + encrypt () + File.Delete plainFilename + decrypt () + assert (File.ReadAllText plainFilename = fileContent) + + printfn "== Altering the MAC..." + writeByteToCipherFileAt 0uy 0L + try + decrypt () + assert false + with + | error -> assert (error :? IntegrityError) + + printfn "== Altering the signature..." + encrypt () + writeByteToCipherFileAt 0uy 32L + try + decrypt () + assert false + with + | error -> assert (error :? SignatureMismatch) + + printfn "== Altering the keys..." + encrypt () + writeByteToCipherFileAt 0uy (32L + 256L) + try + decrypt () + assert false + with + | error -> assert (error :? UnableToDecryptAESKeys) + + printfn "== Altering the cyphering..." + encrypt () + writeByteToCipherFileAt 0uy (32L + 256L + 256L) + try + decrypt () + assert false + with + | error -> assert (error :? IntegrityError) + + File.Delete cipherFilename + File.Delete plainFilename + + printfn "===== API tests OK" diff --git a/labo2-fsharp/labo2-fsharp.userprefs b/labo2-fsharp/labo2-fsharp.userprefs index 5aa50ca..96eeb57 100644 --- a/labo2-fsharp/labo2-fsharp.userprefs +++ b/labo2-fsharp/labo2-fsharp.userprefs @@ -1,19 +1,21 @@  - - + + - - - - + + + + + + - + - - + + diff --git a/labo2-fsharp/run_tests.sh b/labo2-fsharp/run_tests.sh index 3f42fa2..5c000fa 100755 --- a/labo2-fsharp/run_tests.sh +++ b/labo2-fsharp/run_tests.sh @@ -1,17 +1,21 @@ #/usr/bin/env bash -xbuild /p:Configuration=Release labo2-fsharp.sln +xbuild /p:Configuration=Debug labo2-fsharp.sln + +export MONO_TRACE_LISTENER=Console.Error + +CryptoFileTests/bin/Debug/CryptoFileTests.exe tests echo "Plaintext:" cat plaintext.txt echo # Encrypt the file 'plaintext.txt'. -CryptoFileTests/bin/Release/CryptoFileTests.exe encrypt plaintext.txt ciphertext +CryptoFileTests/bin/Debug/CryptoFileTests.exe encrypt plaintext.txt ciphertext # Decrypt the file 'ciphertext' to the directory 'output'. rm -r output mkdir output -CryptoFileTests/bin/Release/CryptoFileTests.exe decrypt ciphertext output +CryptoFileTests/bin/Debug/CryptoFileTests.exe decrypt ciphertext output echo "Decrypted ciphertext:" cat output/plaintext.txt diff --git a/rapport/main.tex b/rapport/main.tex index 1c25220..508355d 100644 --- a/rapport/main.tex +++ b/rapport/main.tex @@ -14,6 +14,7 @@ %%% URLs %%% \urldef{\dotnetcrypto}\url{http://msdn.microsoft.com/en-us/library/System.Security.Cryptography%28v=vs.110%29.aspx} \urldef{\monodevelop}\url{http://www.monodevelop.com/} +\urldef{\rsacryptoserviceprovider}\url{http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider%28v=vs.110%29.aspx} \title{ICR - Labo \#2 : \textit{Conception et implémentation d'un container sécurisé pour des données médicales}} \author{G.Burri} @@ -198,17 +199,17 @@ Deux \emph{assemblies} sont crées : \begin{itemize} \item \emph{CryptoFile} : \emph{Library} mettant à disposition l'\emph{API} de chiffrement de fichier et de déchiffrement de container. - \item \emph{CryptoFileTests} : Exécutable utilisant la \emph{Library} \emph{CryptoFile} et permettant d'utiliser l'\emph{API} à l'aide d'arguments fournis. + \item \emph{CryptoFileTests} : Exécutable utilisant la \emph{library} \emph{CryptoFile} et permettant d'utiliser l'\emph{API} à l'aide d'arguments fournis par la ligne de commande. \end{itemize} \subsection{Utilisation} -Il est possible de compiler la solution à l'aide de \emph{MonoDevelop}\footnote{\monodevelop}. Le script \emph{Bash} \texttt{labo2-fsharp/run\_tests.sh} montre un exemple de compilation à la ligne de commande, puis de chiffrement d'un fichier suivit du déchiffrement du container ainsi créé. +Il est possible de compiler la solution à l'aide de \emph{MonoDevelop}\footnote{\monodevelop}. 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 : \begin{itemize} - \item \texttt{CryptoFileTests/bin/Release/CryptoFileTests.exe tests} : Réalise un série de tests. + \item \texttt{CryptoFileTests/bin/Release/CryptoFileTests.exe tests} : Réalise une série de tests. \item \texttt{CryptoFileTests/bin/Release/CryptoFileTests.exe encrypt } : Chiffre le fichier \texttt{} ver le container \texttt{}. \item \texttt{CryptoFileTests/bin/Release/CryptoFileTests.exe decrypt } : Déchiffre le container \texttt{} dans le dossier \texttt{}. \end{itemize} @@ -223,7 +224,7 @@ La \emph{ĺibrary} \emph{CryptoFile} est composé de trois fichiers : \begin{itemize} \item \emph{Types.fs} : Quelques types publics. \item \emph{Crypto.fs} : Contient toutes les primitives cryptographique nécessaire. - \item \emph{Tests.fs} : Contient quelques tests unitaires du module \emph{Crypto}. + \item \emph{UnitTests.fs} : Contient quelques tests unitaires du module \emph{Crypto}. \item \emph{API.fs} : Contient l'interface publique de la \emph{library}. Elle est détaillée ci après. \end{itemize} @@ -252,13 +253,16 @@ module API = \section{Analyse de la sécurité de l'implémentation} -\subsection{Quelles sont les parties critiques du code ?} +\subsection{Quelles sont les parties critiques du code et comment s'assure-t-on que ces parties soit correctement implémentées ?} -\subsection{Comment s'est-on assuré que ces parties soient correctement implémentées ?} +La génération des clefs \emph{AES} doit être faite avec un générateur cryptographique. Dans notre cas nous utilisons \emph{System.Security.Cryptography.RSACryptoServiceProvider}\footnote{\rsacryptoserviceprovider}. -\subsection{Quels sont les points-faibles restants ?} +La mémoire correspondant aux clefs générées devrait être effacé, dans notre cas si un attaquant a accès à la mémoire de notre programme alors il a accès au contenu des fichiers à chiffrer, il n'y a donc pas de précautions prise en particulier à ce sujet. -\subsection{Quels sont les possibilités pour corriger ces points faibles ?} + +\subsection{Quels sont les points-faibles restants et quelles sont les possibilités de les corriger ?} + +Les deux clefs privées \emph{RSA} doivent absolument rester secrètes, pour ce faire il faudrait chiffrer les fichiers contenant ces clefs à l'aide d'une \emph{passphrase} robuste et garder celle-ci en sécurité. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -- 2.43.0