ARC4

From Crypto++ Wiki
Jump to navigation Jump to search
ARC4
Documentation
#include <cryptopp/arc4.h>

ARC4, ot RC4 is a stream cipher developed by Ron Rivest in 1987 for RSA Data Security Inc. The cipher uses a 40-bit to 2048-bit key, and no initialization vector. RC4 was initially a trade secret, but the source code was subsequently reverse engineered and leaked on the Cypherpunks mailing list. Also see Thank you Bob Anderson.

ARC4 is declared in the Weak namespace. You must define CRYPTOPP_ENABLE_NAMESPACE_WEAK before you include ARC4 header file or use ARC4. You must also declare variables in the weak namespace using Weak::ARC4.

If you are used to working in languages like Java 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 consider using an algorithm or mode like CCM, GCM, EAX or ChaCha20Poly1305.

Key and IV

The first sample program prints ARC4's key and iv sizes.

int main()
{
    using namespace CryptoPP;

    Weak::ARC4::Encryption enc;
    std::cout << "key length: " << enc.DefaultKeyLength() << std::endl;
    std::cout << "key length (min): " << enc.MinKeyLength () << std::endl;
    std::cout << "key length (max): " << enc.MaxKeyLength () << std::endl;
    std::cout << "iv size: " << enc.IVSize() << std::endl;

    return 0;
}

A typical output is shown below. Notice ARC4 does not use an iv.

$ ./test.exe 
key length: 16
key length (min): 1
key length (max): 256
iv size: 0

Encryption and Decryption

The following example shows you how to use Weak::ARC4::Encryption and Weak::ARC4::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 "osrng.h"
#include "files.h"
#include "hex.h"

#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include "arc4.h"

#include <iostream>
#include <string>

int main()
{
    using namespace CryptoPP;

    AutoSeededRandomPool prng;
    HexEncoder encoder(new FileSink(std::cout));
    std::string plain("ARC4 stream cipher test"), cipher, recover;

    SecByteBlock key(16);
    prng.GenerateBlock(key, key.size());

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

    // Encryption object
    Weak::ARC4::Encryption enc;    
    enc.SetKey(key, key.size());

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

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

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

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

    Weak::ARC4::Decryption dec;
    dec.SetKey(key, key.size());

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

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

    return 0;
}

A typical output is shown below.

$ ./test.exe 
Key: 49FB42D76C311EA37FBB4A6F819496F4
Plain: ARC4 stream cipher test
Cipher: 24B99F0ABABAF284F61EB43479E5A8CF108D77354552E6
Self inverting: 1
Resynchronizable: 0
Recovered: ARC4 stream cipher test

Pipelines

You can also use stream ciphers in a Pipeline. Below is an example of ARC4 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 "osrng.h"
#include "files.h"
#include "hex.h"

#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include "arc4.h"

#include <iostream>
#include <string>

int main()
{
    using namespace CryptoPP;

    AutoSeededRandomPool prng;
    HexEncoder encoder(new FileSink(std::cout));
    std::string plain("ARC4 stream cipher test"), cipher, recover;

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

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

    // Encryption object
    Weak::ARC4::Encryption enc;    
    enc.SetKey(key, key.size());

    // Decryption object
    Weak::ARC4::Decryption dec;    
    dec.SetKey(key, key.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[0], 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: EBC47CE30CDAED5612DBD9F55A4048BE2B5B071D1790E39C01D9FCAD62B03B16
Plain: ARC4 stream cipher test
Cipher: 48C6E438C80FEAA18561237012081598FC7779EF6CACF6
Recovered: ARC4 stream cipher test

Discard Bytes

A modified ARC4 algorithm that discard bytes is called "RC4-drop(nbytes)", where nbytes is the number of initial keystream bytes that are dropped. The Standard Cryptographic Algorithm Name (SCAN) default is nbytes = 768 bytes.

You can discard bytes from the keystream using SetKey with NameValuePairs and DiscardBytes parameter. The code below uses the Crypto++ default value for DiscardBytes, which is 0 bytes.

HexEncoder encoder(new FileSink(std::cout));
std::string plain("ARC4 stream cipher test"), cipher, recover;

SecByteBlock key(32);
memset(key, 0x00, key.size());

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

// Encryption object
Weak::ARC4::Encryption enc;    
enc.SetKey(key, key.size());

// Decryption object
Weak::ARC4::Decryption dec;    
dec.SetKey(key, key.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[0], cipher.size());
encoder.MessageEnd();
std::cout << std::endl;

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

The result is:

$ ./test.exe 
Key: 0000000000000000000000000000000000000000000000000000000000000000
Plain: ARC4 stream cipher test
Cipher: 9F4ACA7583442948EF6773473407E205A2685FD795BF9F
Recovered: ARC4 stream cipher test

And the code below discards 2048 bytes. Notice the addition of AlgorithmParameters params.

using namespace CryptoPP;

HexEncoder encoder(new FileSink(std::cout));
std::string plain("ARC4 stream cipher test"), cipher, recover;
AlgorithmParameters params = MakeParameters("DiscardBytes", 2048);

SecByteBlock key(32);
memset(key, 0x00, key.size());

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

// Encryption object
Weak::ARC4::Encryption enc;    
enc.SetKey(key, key.size(), params);

// Decryption object
Weak::ARC4::Decryption dec;    
dec.SetKey(key, key.size(), params);

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[0], cipher.size());
encoder.MessageEnd();
std::cout << std::endl;

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

And the result is:

$ ./test.exe 
Key: 0000000000000000000000000000000000000000000000000000000000000000
Plain: ARC4 stream cipher test
Cipher: 82195259806BAE0C2B66FB7321D7BD0C0004E2090F0739
Recovered: ARC4 stream cipher test