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)
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]
let mac' = Crypto.ComputeHMAC keyMAC inputStream
if mac' <> mac then
raise IntegrityError
-
+
// Authentication validation.
if not <| Crypto.verifySignRSA signaturePubKey mac' signature then
raise SignatureMismatch
<Externalconsole>true</Externalconsole>\r
<Optimize>false</Optimize>\r
<Tailcalls>false</Tailcalls>\r
- <EnvironmentVariables>\r
- <EnvironmentVariables>\r
- <Variable name="MONO_TRACE_LISTENER" value="Console.Error" />\r
- </EnvironmentVariables>\r
- </EnvironmentVariables>\r
- <Commandlineparameters>tests</Commandlineparameters>\r
</PropertyGroup>\r
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">\r
<DebugSymbols>true</DebugSymbols>\r
<Compile Include="AssemblyInfo.fs" />\r
<Compile Include="Types.fs" />\r
<Compile Include="Crypto.fs" />\r
- <Compile Include="Tests.fs" />\r
<Compile Include="API.fs" />\r
+ <Compile Include="UnitTests.fs" />\r
</ItemGroup>\r
<Import Project="$(MSBuildExtensionsPath32)\..\Microsoft F#\v4.0\Microsoft.FSharp.Targets" />\r
</Project>
\ No newline at end of file
+++ /dev/null
-namespace CryptoFile
-
-module Tests =
- 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"
-
- let testRSASignature () =
- let kpub, kpriv = generateRSAKeysPair
- let plaintext = "Hello, World!"
- let sha256 = new SHA256Managed ()
- let signature = signRSA kpriv (sha256.ComputeHash (Encoding.UTF8.GetBytes plaintext))
- assert verifySignRSA kpub (sha256.ComputeHash (Encoding.UTF8.GetBytes plaintext)) signature
- assert not (verifySignRSA kpub (sha256.ComputeHash (Encoding.UTF8.GetBytes "Hello!")) signature)
- printfn "testRSASignature OK"
-
- let runAllTests () =
- testRSA ()
- testRSASignature ()
\ No newline at end of file
exception IntegrityError
exception SignatureMismatch
+exception UnableToDecryptAESKeys
--- /dev/null
+namespace CryptoFile
+
+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"
+
+ let testRSASignature () =
+ let kpub, kpriv = generateRSAKeysPair
+ let plaintext = "Hello, World!"
+ let sha256 = new SHA256Managed ()
+ let signature = signRSA kpriv (sha256.ComputeHash (Encoding.UTF8.GetBytes plaintext))
+ assert verifySignRSA kpub (sha256.ComputeHash (Encoding.UTF8.GetBytes plaintext)) signature
+ assert not (verifySignRSA kpub (sha256.ComputeHash (Encoding.UTF8.GetBytes "Hello!")) signature)
+ printfn "testRSASignature OK"
+
+ 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
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
- <ProjectGuid>{FA5B9C91-036B-455C-892B-05A7FC398158}</ProjectGuid>
- <OutputType>Exe</OutputType>
- <RootNamespace>CryptoFileTests</RootNamespace>
- <AssemblyName>CryptoFileTests</AssemblyName>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug</OutputPath>
- <DefineConstants>DEBUG</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <Externalconsole>true</Externalconsole>
- <Tailcalls>false</Tailcalls>
- <PlatformTarget>x86</PlatformTarget>
- <Commandlineparameters>tests</Commandlineparameters>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
- <DebugSymbols>false</DebugSymbols>
- <DebugType>none</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release</OutputPath>
- <ErrorReport>prompt</ErrorReport>
- <PlatformTarget>x86</PlatformTarget>
- <Externalconsole>true</Externalconsole>
- <Tailcalls>true</Tailcalls>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="mscorlib" />
- <Reference Include="FSharp.Core" />
- <Reference Include="System" />
- <Reference Include="System.Core" />
- <Reference Include="System.Numerics" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="AssemblyInfo.fs" />
- <Compile Include="Program.fs" />
- </ItemGroup>
- <Import Project="$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets" />
- <ItemGroup>
- <ProjectReference Include="..\CryptoFile\CryptoFile.fsproj">
- <Project>{CDB168EA-04F9-4A8B-A3B4-27D9A6390269}</Project>
- <Name>CryptoFile</Name>
- </ProjectReference>
- </ItemGroup>
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+ <PropertyGroup>\r
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>\r
+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>\r
+ <ProjectGuid>{FA5B9C91-036B-455C-892B-05A7FC398158}</ProjectGuid>\r
+ <OutputType>Exe</OutputType>\r
+ <RootNamespace>CryptoFileTests</RootNamespace>\r
+ <AssemblyName>CryptoFileTests</AssemblyName>\r
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\r
+ </PropertyGroup>\r
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">\r
+ <DebugSymbols>true</DebugSymbols>\r
+ <DebugType>full</DebugType>\r
+ <Optimize>false</Optimize>\r
+ <OutputPath>bin\Debug</OutputPath>\r
+ <DefineConstants>DEBUG</DefineConstants>\r
+ <ErrorReport>prompt</ErrorReport>\r
+ <Externalconsole>true</Externalconsole>\r
+ <Tailcalls>false</Tailcalls>\r
+ <PlatformTarget>x86</PlatformTarget>\r
+ <Commandlineparameters>tests</Commandlineparameters>\r
+ <EnvironmentVariables>\r
+ <EnvironmentVariables>\r
+ <Variable name="MONO_TRACE_LISTENER" value="Console.Error" />\r
+ </EnvironmentVariables>\r
+ </EnvironmentVariables>\r
+ </PropertyGroup>\r
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">\r
+ <DebugSymbols>false</DebugSymbols>\r
+ <DebugType>none</DebugType>\r
+ <Optimize>true</Optimize>\r
+ <OutputPath>bin\Release</OutputPath>\r
+ <ErrorReport>prompt</ErrorReport>\r
+ <PlatformTarget>x86</PlatformTarget>\r
+ <Externalconsole>true</Externalconsole>\r
+ <Tailcalls>true</Tailcalls>\r
+ </PropertyGroup>\r
+ <ItemGroup>\r
+ <Reference Include="mscorlib" />\r
+ <Reference Include="FSharp.Core" />\r
+ <Reference Include="System" />\r
+ <Reference Include="System.Core" />\r
+ <Reference Include="System.Numerics" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <Compile Include="AssemblyInfo.fs" />\r
+ <Compile Include="Tests.fs" />\r
+ <Compile Include="Program.fs" />\r
+ </ItemGroup>\r
+ <Import Project="$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets" />\r
+ <ItemGroup>\r
+ <ProjectReference Include="..\CryptoFile\CryptoFile.fsproj">\r
+ <Project>{CDB168EA-04F9-4A8B-A3B4-27D9A6390269}</Project>\r
+ <Name>CryptoFile</Name>\r
+ </ProjectReference>\r
+ </ItemGroup>\r
</Project>
\ No newline at end of file
| _ ->
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"
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 ()
--- /dev/null
+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"
<Properties>
- <MonoDevelop.Ide.Workspace ActiveConfiguration="Release|x86" />
- <MonoDevelop.Ide.Workbench ActiveDocument="CryptoFile/API.fs">
+ <MonoDevelop.Ide.Workspace ActiveConfiguration="Debug|x86" />
+ <MonoDevelop.Ide.Workbench ActiveDocument="CryptoFile/UnitTests.fs">
<Files>
- <File FileName="CryptoFile/Types.fs" Line="1" Column="1" />
- <File FileName="CryptoFile/API.fs" Line="36" Column="36" />
- <File FileName="CryptoFile/Crypto.fs" Line="97" Column="97" />
- <File FileName="CryptoFile/Tests.fs" Line="25" Column="25" />
+ <File FileName="CryptoFile/UnitTests.fs" Line="40" Column="40" />
+ <File FileName="CryptoFile/Crypto.fs" Line="27" Column="27" />
+ <File FileName="CryptoFile/Types.fs" Line="33" Column="33" />
+ <File FileName="run_tests.sh" Line="26" Column="26" />
+ <File FileName="CryptoFileTests/Program.fs" Line="20" Column="20" />
+ <File FileName="CryptoFile/API.fs" Line="98" Column="98" />
<File FileName="CryptoFileTests/AssemblyInfo.fs" Line="7" Column="7" />
- <File FileName="CryptoFileTests/Program.fs" Line="5" Column="5" />
+ <File FileName="CryptoFileTests/Tests.fs" Line="44" Column="44" />
</Files>
<Pads>
<Pad Id="ProjectPad">
<State expanded="True">
- <Node name="CryptoFile" expanded="True" selected="True" />
- <Node name="CryptoFileTests" expanded="True" />
+ <Node name="CryptoFile" expanded="True" />
+ <Node name="CryptoFileTests" expanded="True" selected="True" />
</State>
</Pad>
</Pads>
#/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
%%% 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}
\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 <file> <container>} : Chiffre le fichier \texttt{<file>} ver le container \texttt{<container>}.
\item \texttt{CryptoFileTests/bin/Release/CryptoFileTests.exe decrypt <container> <output directory>} : Déchiffre le container \texttt{<container>} dans le dossier \texttt{<output directory>}.
\end{itemize}
\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}
\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é.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%