Compilation de CryptoPP

La version de CryptoPP utilisée est la 5.6.2. Il s'agit d'un simple fichier ZIP avec les sources à compiler.

wget "http://downloads.sourceforge.net/project/cryptopp/cryptopp/5.6.2/cryptopp562.zip"
unzip "cryptopp562.zip" -d "cryptopp"
cd "cryptopp"
make -j9

Une fois ces commandes exécutées, la librairie est compilée et le fichier libcryptopp.a devrait exister.

Vecteur d'initialisation

L'algorithme AES fonctionne par bloc et, suivant le mode d'opération choisi (dans notre cas, CFB), a besoin d'un vecteur d'initialisation. Ce vecteur doit être composé de 16 caractères et le même doit être utilisé pour le chiffrage et déchiffrage. A noter que ce vecteur peut être rendu publique sans compromettre la sécurité des données chiffrées.

byte* generateRandomIV(void) {
    AutoSeededRandomPool rnd;
    byte* iv = new byte[AES::BLOCKSIZE+1];
    rnd.GenerateBlock(iv, AES::BLOCKSIZE);
    iv[AES::BLOCKSIZE] = '\0';
    return iv;
}

Cette fonction va générer un vecteur d'initialisation aléatoire, grâce à une fonction fournie par CryptoPP. Le type byte* correspond à un unsigned char*.

Clé privée

C'est cette valeur qui est essentielle pour assurer la confidentialité des données et qui ne doit pas être divulguée. CryptoPP supporte des clés de 16 (128 bits), 24 (192 bits) ou 32 caractères (256 bits).

byte* generateRandomKey(void) {
    AutoSeededRandomPool rnd;
    byte* key = new byte[AES::DEFAULT_KEYLENGTH+1];
    rnd.GenerateBlock(key, AES::DEFAULT_KEYLENGTH);
    key[AES::DEFAULT_KEYLENGTH] = '\0';
    return key;
}

Pour l'exercice, cette fonction génère également une clé privée aléatoire, qui devra être la même pour le déchiffrage. La constante AES::DEFAULT_KEYLENGTH correspond à 16 caractères.

Chiffrage et déchiffrage des données

Sitôt que toutes les données sont connues, le chiffrage est assez simple à appliquer:

byte* encrypt(byte* iv, byte* key, int keyLength, byte* data, int dataLength) {
    byte* out = new byte[dataLength];
    CFB_Mode<AES>::Encryption cfbEncryption(key, keyLength, iv);
    cfbEncryption.ProcessData(out, data, dataLength);
    return out;
}

Cette fonction va retourner un tableau de la même taille que l'input, chiffré avec le vecteur d'initialisation et la clé spécifiée. Le déchiffrage fonctionne de la même manière:

byte* decrypt(byte* iv, byte* key, int keyLength, byte* cipher, int cipherLength) {
    byte* plain = new byte[cipherLength];
    CFB_Mode<AES>::Decryption cfbDecryption(key, keyLength, iv);
    cfbDecryption.ProcessData(plain, cipher, cipherLength);
    return plain;
}

Utilisation

Toujours pour l'exercice, j'ai créé la fonction main suivante qui permet de spécifier une chaîne à chiffrer ainsi qu'un clé de 16 caractères:

int main(int argc, char* argv[]) {
    byte* iv = generateRandomIV();
    byte* key = generateRandomKey();
 
    char* input = "hello, world!";
    if (argc > 1) { input = argv[1]; }
    if (argc > 2) {
        char* ikey = argv[2];
        int klen = strlen(ikey);
        if (klen!=AES::DEFAULT_KEYLENGTH) {
            cerr << "Key must be of length " << AES::DEFAULT_KEYLENGTH << " but was of length " << klen << endl;
            return 1;
        }
        delete[] key;
        key = reinterpret_cast<byte*>(ikey);
    }
 
    int len = strlen(input);
 
    byte* init = reinterpret_cast<byte*>(input);
    byte* cipher = encrypt(iv, key, AES::DEFAULT_KEYLENGTH, init, len);
    byte* plain = decrypt(iv, key, AES::DEFAULT_KEYLENGTH, cipher, len);
 
    cout << "Block size: " << AES::BLOCKSIZE << endl;
    cout << "Default key length: " << AES::DEFAULT_KEYLENGTH << endl;
    cout << "Min key length: " << AES::MIN_KEYLENGTH << endl;
    cout << "Max key length: " << AES::MAX_KEYLENGTH << endl;
    cout << "--------------------------------------" << endl;
    cout << "Input: " << init << endl;
    cout << "Key: " << key << endl;
    cout << "Cipher: " << cipher << endl;
    cout << "Plain: " << plain << endl;
 
    delete[] cipher;
    delete[] plain;
    delete[] iv;
 
    return 0;
}

Pour compiler le programme, il suffit d'exécuter la ligne suivante:

g++ -I "cryptopp" "main.cpp" -o "crypt" "cryptopp/libcryptopp.a"

Une fois que la compilation est faite, voici un exemple d'utilisation avec son output:

./crypt "AStorm fôr aïver" "0123456789ABCDEF"
Block size: 16
Default key length: 16
Min key length: 16
Max key length: 32
--------------------------------------
Input: AStorm fôr aïver
Key: 0123456789ABCDEF
Cipher: [binary data]
Plain: AStorm fôr aïver

Pour plus d'informations, je me suis servi de ce lien et de celui-ci pour les différents morceaux de code.