Advanced Encryption Standard

From Crypto++ Wiki
(Redirected from AES)
Jump to navigation Jump to search
AES
Documentation
#include <cryptopp/rijndael.h>

The Advanced Encryption Standard, or AES, is a NIST approved block cipher specified in FIPS 197, Advanced Encryption Standard (AES).

When using AES, one typically specifies a mode of operation and optionally a padding scheme. AES provides confidentiality only using most modes of operation such as ECB and CBC. When operating the cipher in CCM, GCM, or EAX mode, the mode provides both confidentiality and authenticity.

Strong Security

If your project is using encryption alone to secure your data, encryption alone is usually not enough. Please take a moment to read Authenticated Encryption and consider using an algorithm or mode like CCM, GCM, EAX or ChaCha20Poly1305. Authenticated encryption provides a MAC over the cipher text to transmission errors and detect tampering.

Even better, consider using an Integrated Encryption Scheme (IES), such as Elliptic Curve Integrated Encryption Scheme (ECIES) or Discrete Logarithm Integrated Encryption Scheme (DLIES). An IES scheme is a hybrid encryption scheme that uses both public keys and secret keys. The scheme is IND-CCA2, which means it provides indistinguishability (IND) under adaptive Chosen Ciphertext Attacks (CCA2).

Sample Programs

There are three sample programs. The first shows AES key and block sizes. The second and third use filters in a pipeline). Pipelining is a high level abstraction and it handles buffering input, buffering output and padding for you.

If you are benchmarking then you may want to visit Benchmarks | Sample Program . It shows you how to use StreamTransformation::ProcessString method to process blocks at a time. Calling a cipher's ProcessString or ProcessBlock eventually call a cipher's ProcessAndXorBlock or AdvancedProcessBlocks, and they are the lowest level API you can use.

The first example dumps the minimum, maximum, and default key lengths used by AES.

cout << "key length: " << AES::DEFAULT_KEYLENGTH << endl;
cout << "key length (min): " << AES::MIN_KEYLENGTH << endl;
cout << "key length (max): " << AES::MAX_KEYLENGTH << endl;
cout << "block size: " << AES::BLOCKSIZE << endl;

Output from the above snippet produces the following. Notice the default key size is 128 bits or 16 bytes.

key length: 16
key length (min): 16
key length (max): 32
block size: 16

The following program shows how to operate AES in CBC mode using a pipeline. The key is declared on the stack using a SecByteBlock to ensure the sensitive material is zeroized. Similar could be used for both plain text and recovered text.

#include "cryptlib.h"
#include "rijndael.h"
#include "modes.h"
#include "files.h"
#include "osrng.h"
#include "hex.h"

#include <iostream>
#include <string>

int main(int argc, char* argv[])
{
    using namespace CryptoPP;

    AutoSeededRandomPool prng;
    HexEncoder encoder(new FileSink(std::cout));

    SecByteBlock key(AES::DEFAULT_KEYLENGTH);
    SecByteBlock iv(AES::BLOCKSIZE);

    prng.GenerateBlock(key, key.size());
    prng.GenerateBlock(iv, iv.size());

    std::string plain = "CBC Mode Test";
    std::string cipher, recovered;

    std::cout << "plain text: " << plain << std::endl;

    /*********************************\
    \*********************************/

    try
    {
        CBC_Mode< AES >::Encryption e;
        e.SetKeyWithIV(key, key.size(), iv);

        StringSource s(plain, true, 
            new StreamTransformationFilter(e,
                new StringSink(cipher)
            ) // StreamTransformationFilter
        ); // StringSource
    }
    catch(const Exception& e)
    {
        std::cerr << e.what() << std::endl;
        exit(1);
    }

    /*********************************\
    \*********************************/

    std::cout << "key: ";
    encoder.Put(key, key.size());
    encoder.MessageEnd();
    std::cout << std::endl;

    std::cout << "iv: ";
    encoder.Put(iv, iv.size());
    encoder.MessageEnd();
    std::cout << std::endl;

    std::cout << "cipher text: ";
    encoder.Put((const byte*)&cipher[0], cipher.size());
    encoder.MessageEnd();
    std::cout << std::endl;
    
    /*********************************\
    \*********************************/

    try
    {
        CBC_Mode< AES >::Decryption d;
        d.SetKeyWithIV(key, key.size(), iv);

        StringSource s(cipher, true, 
            new StreamTransformationFilter(d,
                new StringSink(recovered)
            ) // StreamTransformationFilter
        ); // StringSource

        std::cout << "recovered text: " << recovered << std::endl;
    }
    catch(const Exception& e)
    {
        std::cerr << e.what() << std::endl;
        exit(1);
    }

    return 0;
}

A typical output is shown below. Note that each run will produce different results because the key and initialization vector are randomly generated.

$ ./test.exe
plain text: CBC Mode Test
key: 01AAD7DB7831A398088EBBA9A3C85546
iv: 13BB6FCB744663EC2A9EF711FA934BAA
cipher text: 8BCD1071F06813F1DEC5FB727F7451E3
recovered text: CBC Mode Test

By switching to EAX mode, authenticity assurances can placed on the cipher text for nearly no programming costs. Below the StreamTransformationFilter was replaced by AuthenticatedEncryptionFilter and AuthenticatedDecryptionFilter.

EAX< AES >::Encryption e;
e.SetKeyWithIV(key, key.size(), iv);

StringSource(plain, true, 
    new AuthenticatedEncryptionFilter(e,
        new StringSink(cipher)
    ) // StreamTransformationFilter
); // StringSource

...

EAX< AES >::Decryption d;
d.SetKeyWithIV(key, key.size(), iv);

StringSource s(cipher, true, 
    new AuthenticatedDecryptionFilter(d,
        new StringSink(recovered)
    ) // StreamTransformationFilter
); // StringSource

Typical output is as follows. Notice the additional cipher text bytes due to the MAC bytes. See EAX Mode for details.

$ ./test.exe
plain text: EAX Mode Test
key: 7787AEA1124566CD3B21265482118404
iv: 8D8430274A49D4DF282218BF4DB40598
cipher text: D8B0C7B3BFF2BBB7F357BEA46F713865823B687E33A0DB63FCD07B0CEA
recovered text: EAX Mode Test

To manually insert bytes into the filter, perform multiple Puts. Though Get is used below, a StringSink could easily be attached and save the administrivia.

const size_t SIZE = 16 * 4;
string plain(SIZE, 0x00);

for(size_t i = 0; i < plain.size(); i++)
    plain[i] = 'A' + (i%26);
...

CBC_Mode < AES >::Encryption encryption(key, sizeof(key), iv);
StreamTransformationFilter encryptor(encryption, NULL);

for(size_t j = 0; j < plain.size(); j++)
    encryptor.Put((byte)plain[j]);

encryptor.MessageEnd();
size_t ready = encryptor.MaxRetrievable();

string cipher(ready, 0x00);
encryptor.Get((byte*) &cipher[0], cipher.size());

Downloads

AES-GCM-Test.zip - Demonstrates encryption and decryption using AES in GCM mode (confidentiality and authentication)

AES-CCM-Test.zip - Demonstrates encryption and decryption using AES in CCM mode (confidentiality and authentication)

AES-EAX-Test.zip - Demonstrates encryption and decryption using AES in EAX mode (confidentiality and authentication)

AES-ECB-Filter.zip - Demonstrates encryption and decryption using AES in ECB mode with filters (confidentiality only)

AES-CBC-Filter.zip - Demonstrates encryption and decryption using AES in CBC mode with filters (confidentiality only)

AES-CFB-Filter.zip - Demonstrates encryption and decryption using AES in CFB mode with filters (confidentiality only)

AES-OFB-Filter.zip - Demonstrates encryption and decryption using AES in OFB mode with filters (confidentiality only)

AES-CTR-Filter.zip - Demonstrates encryption and decryption using AES in CTR mode with filters (confidentiality only)