Salsa20

From Crypto++ Wiki
Jump to: navigation, search

Salsa20 is a stream cipher by Daniel J. Bernstein and part of the eSTREAM portfolio. The 20-round stream cipher Salsa20/20 is consistently faster than AES and is recommended by the designer for typical cryptographic applications. The reduced-round ciphers Salsa20/12 and Salsa20/8 are among the fastest 256-bit stream ciphers available and are recommended for applications where speed is more important than confidence. Also see The Salsa20 family of stream ciphers.

Salsa20 provides a 8, 12 or 20 rounds. The default number of rounds is 20. The sample program below shows you how to change the number of rounds.

If you are used to working in languages like Jave or libraries like OpenSSL, then you might want to visit the Init-Update-Final wiki page. Crypto++ provides the transformation model, but its not obvious because its often shrouded behind Pipelines.

Note: 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 consider using a block cipher and mode like CCM, GCM, or EAX.

Encryption and Decryption

The following example shows you how to use Salsa20::Encryption and Salsa20::Decryption. &cipher[0] may look odd, but its how to get the non-const pointer from a std::string.

#include "cryptlib.h"
#include "secblock.h"
#include "salsa.h"
#include "osrng.h"

#include <iostream>
#include <string>

int main()
{
    using namespace CryptoPP;

    AutoSeededRandomPool prng;
    std::string plain("My Plaintext!! My Dear plaintext!!"), cipher, recover;

    SecByteBlock key(32), iv(8);
    prng.GenerateBlock(key, key.size());
    prng.GenerateBlock(iv, iv.size());

    // Encryption object
    Salsa20::Encryption enc;    
    enc.SetKeyWithIV(key, key.size(), iv, iv.size());

    // Perform the encryption
    cipher.resize(plain.size());
    enc.ProcessData((byte*)&cipher[0], (const byte*)plain.data(), plain.size());

    std::cout << "Plain: " << plain << std::endl;
    std::cout << "Cipher: " << cipher << std::endl;

    Salsa20::Decryption dec;
    dec.SetKeyWithIV(key, key.size(), iv, iv.size());

    // Perform the decryption
    recover.resize(cipher.size());
    dec.ProcessData((byte*)&recover[0], (const byte*)cipher.data(), cipher.size());

    std::cout << "Recovered: " << recover << std::endl;

    return 0;
}

A typical output is shown below, including the non-printable characters from encryption.

$ ./test.exe
Plain: My Plaintext!! My Dear plaintext!!
Cipher: '"▒ç]▒▒ѱ▒▒Ȏ▒▒T▒▒▒▒▒▒­▒&
                               ▒q▒▒▒
Recovered: My Plaintext!! My Dear plaintext!!

Resynchronizing

The Salsa family is both self-inverting and resynchronizable so you can use the encryption object for decryption, too.

#include "cryptlib.h"
#include "secblock.h"
#include "salsa.h"
#include "osrng.h"

#include <iostream>
#include <string>

int main()
{
    using namespace CryptoPP;

    AutoSeededRandomPool prng;
    std::string plain("My Plaintext!! My Dear plaintext!!"), cipher, recover;

    SecByteBlock key(32), iv(8);
    prng.GenerateBlock(key, key.size());
    prng.GenerateBlock(iv, iv.size());

    // Encryption object
    Salsa20::Encryption enc;    
    enc.SetKeyWithIV(key, key.size(), iv, iv.size());

    // Perform the encryption
    cipher.resize(plain.size());
    enc.ProcessData((byte*)&cipher[0], (const byte*)plain.data(), plain.size());

    std::cout << "Plain: " << plain << std::endl;
    std::cout << "Cipher: " << cipher << std::endl;

    // Salsa20::Decryption dec;
    // dec.SetKeyWithIV(key, key.size(), iv, iv.size());

    std::cout << "Self inverting: " << enc.IsSelfInverting() << std::endl;
    std::cout << "Resynchronizable: " << enc.IsResynchronizable() << std::endl;

    enc.Resynchronize(iv, iv.size());

    // Perform the decryption
    // recover.resize(cipher.size());
    // dec.ProcessData((byte*)&recover[0], (const byte*)cipher.data(), cipher.size());

    // Perform the decryption with the decryptor
    recover.resize(cipher.size());
    enc.ProcessData((byte*)&recover[0], (const byte*)cipher.data(), cipher.size());

    std::cout << "Recovered: " << recover << std::endl;

    return 0;
}

A typical output is shown below, including the non-printable characters from encryption.

$ ./test.exe
Plain: My Plaintext!! My Dear plaintext!!
Cipher: p▒3▒?▒▒I▒.D▒>▒▒▒▒Dx$E▒5▒▒p▒6▒[▒▒
Self inverting: 1
Resynchronizable: 1
Recovered: My Plaintext!! My Dear plaintext!!

Pipelines

You can also use stream ciphers in a Pipeline. Below is an example of Salsa20 participating in a pipeline. Internally, StreamTransformationFilter calls ProcessData on the incoming data stream. The filter also buffers output if there is no attached transformation or sink.

#include "cryptlib.h"
#include "secblock.h"
#include "filters.h"
#include "salsa.h"
#include "osrng.h"
#include "files.h"
#include "hex.h"

#include <iostream>
#include <string>

int main()
{
    using namespace CryptoPP;

    AutoSeededRandomPool prng;
    HexEncoder encoder(new FileSink(std::cout));
    std::string plain("My Plaintext!! My Dear plaintext!!"), cipher, recover;

    SecByteBlock key(32), iv(8);
    prng.GenerateBlock(key, key.size());
    prng.GenerateBlock(iv, iv.size());

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

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

    // Encryption object
    Salsa20::Encryption enc;    
    enc.SetKeyWithIV(key, key.size(), iv, iv.size());

    // Decryption object
    Salsa20::Decryption dec;    
    dec.SetKeyWithIV(key, key.size(), iv, iv.size());

    StringSource ss1(plain, true, new StreamTransformationFilter(enc, new StringSink(cipher)));
    StringSource ss2(cipher, true, new StreamTransformationFilter(dec, new StringSink(recover)));

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

    std::cout << "Cipher: ";
    encoder.Put((const byte*)cipher.data(), cipher.size());
    encoder.MessageEnd();
    std::cout << std::endl;

    std::cout << "Recovered: " << recover << std::endl;

    return 0;
}

The program produces the expected output:

$ ./test.exe
Key: 16FE53114067E535C712A99781C18E8246CECEF354D334304B7B580F2B1DA495
IV: 105BC9A388E0D226
Plain: My Plaintext!! My Dear plaintext!!
Cipher: 19D12B9C2621A2E48FF3B14634530CA3EA7FBDB2FF48FBDC86FDDA1129B9A7B9992E
Recovered: My Plaintext!! My Dear plaintext!!

Rounds

If you need to set the number of rounds you have two choices. First, you can use SetKeyWithRounds . Second, you can use NameValuePairs and SetKey. Below is an example of the second method.

SecByteBlock key(32);
AlgorithmParameters params = MakeParameters("Rounds", 8);

Salsa20::Encryption salsa;
salsa.SetKey(key, key.size(), params);