SIMON

From Crypto++ Wiki
Jump to navigation Jump to search
SIMON64 and SIMON128
Documentation
#include <cryptopp/simon.h>

SIMON64 and SIMON128 are lightweight block ciphers designed by Ray Beaulieu, Douglas Shors, Jason Smith, Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. The SIMON and SPECK homepage is located at http://iadgov.github.io/simon-speck. The ciphers were designed for resource constrained devices and gadgets that participate in the Internet of Things. NIST is considering applications of lightweight cryptography for sensor networks, healthcare and the smart grid. NASA has expanding programs for small satellites such as CubeSats which may need lightweight algorithms.

One of the security goals of SIMON was maintain an acceptable level of security in an environment where power, memory and processors were [sometimes severely] limited. The ciphers are associated with the NSA so there is some controversy about them. The ciphers also have a number of good attributes so speculation should not be hard to overcome. Also see Notes on the design and analysis of Simon and Speck. Linux also added SPECK support for efficient, opportunistic encryption on low-resource devices to the kernel in February 2018.

The Crypto++ library offers SIMON-64 and SIMON-128 because they employ 32-bit and 64-bit words. Also see Issue 539 which tracked the addition and Commit 3970a066e35f. The library does not offer SIMON-48 and SIMON-96 because of the unusual 24-bit and 48-bit word sizes. SIMON-48 and SIMON-96 are technically feasible but are likely inefficient on commodity hardware.

The library's SSSE3 implementation of SIMON-128 runs at about 6 cycles per byte (cpb) on a modern Skylake machine. It is 2 or 3 cpb slower than the Simon team's SSE4 implementation. To improve speed the library needs to switch to a bit-sliced implementation. We likely will not cut-over to the bit-sliced implementation for two reasons. First, Simon does not use lookup tables so bit-slicing is not required to contain side channel threats. Second, Simon performs well already.

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 understand why you should prefer to use CCM, GCM, or EAX over other modes, such as CBC or CTR.

Note: Simon and Speck were added at Crypto++ 6.0. We call the 6.0 implementation the "big-endian" implementation because it arrived at the test vector results published in the paper, and the test vectors were in big-endian format. Our implementation was wrong because we failed to follow the algorithmic description provided in the paper. At Crypto++ 6.1 we switched to a "little-endian" implementation, which followed the algorithmic description from the the paper. The little-endian version fails to arrive at the test vector results, but it agrees with the paper and the kernel's implementation. Also see Issue 585.

Algorithm Name

If you call StaticAlgorithmName then the function will return the partial name "SIMON-<block size>". Once the cipher is keyed you can call AlgorithmName which returns the full name presented as "SIMON-<block size>(<key length>)". In the case of SIMON the algorithms names are SIMON-64(96), SIMON-64(128), SIMON-128(128), SIMON-128(192) and SIMON-128(256).

The naming follows DSTU 7624:2014, where block size is provided first and then key length. The library uses a dash to identify block size and parenthesis to identify key length. For example, Kalyna-128(256) is Kalyna with a 128-bit block size and a 256-bit key length. If a mode is associated with the object, then it follows as expected. For example, Kalyna-256(512)/ECB denotes Kalyna with a 256-bit block and 512-bit key operated in ECB mode.

int main(int argc, char* argv[])
{
    SIMON128::Encryption simon;

    std::cout << "StaticAlgorithmName: " << simon.StaticAlgorithmName() << std::endl;
    std::cout << "AlgorithmName (unkeyed): " << simon.AlgorithmName() << std::endl;

    byte key[SIMON128::DEFAULT_KEYLENGTH] = {};
    simon.SetKey(key, sizeof(key));

    std::cout << "AlgorithmName (keyed): " << simon.AlgorithmName() << std::endl;

    return 0;
}

The program results in the following output.

$ ./test.exe
StaticAlgorithmName: SIMON-128
AlgorithmName (unkeyed): SIMON-128
AlgorithmName (keyed): SIMON-128(128)

Sample Programs

There are three sample programs. The first shows SIMON 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 snippet dumps the minimum, maximum, and default key lengths used by SIMON128.

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

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

$ ./test.exe
key length: 16
key length (min): 16
key length (max): 32
block size: 16

The following program shows how to operate SIMON128 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.

AutoSeededRandomPool prng;

SecByteBlock key(SIMON128::DEFAULT_KEYLENGTH);
prng.GenerateBlock(key, key.size());

byte iv[SIMON128::BLOCKSIZE];
prng.GenerateBlock(iv, sizeof(iv));

string plain = "CBC Mode Test";
string cipher, encoded, recovered;

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

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

    CBC_Mode< SIMON128 >::Encryption e;
    e.SetKeyWithIV(key, key.size(), iv);

    // The StreamTransformationFilter adds padding
    //  as required. ECB and CBC Mode must be padded
    //  to the block size of the cipher.
    StringSource(plain, true, 
        new StreamTransformationFilter(e,
            new StringSink(cipher)
        ) // StreamTransformationFilter
    ); // StringSource
}
catch(const CryptoPP::Exception& e)
{
    cerr << e.what() << std::endl;
    exit(1);
}

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

// Pretty print
StringSource(cipher, true,
    new HexEncoder(
        new StringSink(encoded)
    ) // HexEncoder
); // StringSource

std::cout << "cipher text: " << encoded << std::endl;

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

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

    // The StreamTransformationFilter removes
    //  padding as required.
    StringSource s(cipher, true, 
        new StreamTransformationFilter(d,
            new StringSink(recovered)
        ) // StreamTransformationFilter
    ); // StringSource

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

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

p$ ./test.exe
Key: 90FFDA466130444D91A12EA6B70ADD1B
IV: B6E3F0FB0CFAE2F88D50F71BA25554CB
plain text: CBC Mode Test
cipher text: A97DEAA287F08FC3E729E981DE675E0C
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< SIMON128 >::Encryption e;
e.SetKeyWithIV(key, key.size(), iv);

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

...

EAX< SIMON128 >::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
Key: 92C02339A7CA9C7A7C238962EDEC3C66
IV: 5524981FA5A300F4781184BB784E0E30
plain text: EAX Mode Test
cipher text: 0EED470309D3EDB7782B544D8784B85F11813089D144414C6C3B789C4C
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 < SIMON128 >::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());

Validation

The Simon and Speck implementations can be tested with the cryptest.exe program. The program validates against modified test vectors from the Simon and Speck paper. Each test vector presented in the paper was modified to little-endian format.

There was one test vector for each block size and key size. After we had one working test vector we generated additional test vectors for later use. The additional test vectors are located at TestVectors/simon.txt and TestVectors/speck.txt.

The program used to generate the test vectors is available at Noloader | simon-speck-supercop. See the files simon-tv.cxx and speck-tv.cxx.

$ ./cryptest.exe tv simon
Using seed: 1519379541

Testing SymmetricCipher algorithm SIMON-64/ECB.
................
Testing SymmetricCipher algorithm SIMON-64/CBC.
..............
Testing SymmetricCipher algorithm SIMON-64/CTR.
..............
Testing SymmetricCipher algorithm SIMON-128/ECB.
........................
Testing SymmetricCipher algorithm SIMON-128/CBC.
.....................
Testing SymmetricCipher algorithm SIMON-128/CTR.
.....................
Tests complete. Total tests = 110. Failed tests = 0.

A modified test vector from the Simon and Speck paper includes the work modified in the Source:

Source: Simon and Simon paper, Appendix B (modified)
Comment: SIMON-64/ECB, 96-bit key
Key: 00010203 08090A0B 10111213
Plaintext: 636C696E 6720726F
Ciphertext: C88F1A11 7FE2A25C

A Crypto++ generated test vector says so in the source:

Source: Crypto++ 6.0 generated
Comment: SIMON-64/ECB, 96-bit key
Key: C04DDD70 D26730FD 7FE0B451
Plaintext: FD7E2EE5 4B1EBEF8
Ciphertext: 570B1682 A037E68D

Downloads

No downloads.