SKIPJACK

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

SKIPJACK is a block cipher developed by the National Security Agency and publicly released in 1998. The cipher has a fixed 10-byte (80-bit) key length and fixed 8-byte (64-bit) block size. Skipjack provides about 80-bits of security and is no longer considered secure.

Bruce Schneier provides some history of the cipher at Declassifying Skipjack. Schneier offers a link to a reference implementation at ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/skipjack. The site offers two source files - skipjack.c and skipjack-orig.c. skipjack.c is an optimized implementation, and skipjack-orig.c is a reference implementation.

The Crypto++ implementation conforms to NIST's SKIPJACK and KEA Algorithm Specifications released in May 1998, and uses test vectors from SP800-17, Modes of Operation Validation System (MOVS): Requirements and Procedures (Table 6, pp. 140-42). skipjack.c and skipjack-orig.c are not consitent with the Crypto++ implementation, and they fail to validate against the NIST test vectors.

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.

SKIPJACK classes

SKIPJACK provides three classes of interest. The first is the SKIPJACK class, the second is SKIPJACK::Encryption class, and the final is the SKIPJACK::Decryption class.

You use the classes just like any other block cipher.

Algorithm Name

StaticAlgorithmName and AlgorithmName return SKIPJACK.

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

    SKIPJACK::Encryption skipjack;

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

    byte key[SKIPJACK::DEFAULT_KEYLENGTH];
    skipjack.SetKey(key, sizeof(key));

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

    return 0;
}

The program results in the following output.

$ ./test.exe
StaticAlgorithmName: SKIPJACK
AlgorithmName (unkeyed): SKIPJACK
AlgorithmName (keyed): SKIPJACK

Sample Programs

There are three sample programs. The first shows SKIPJACK 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 program prints key and block size for the cipher.

int main(int argc, char* argv[])
{
    std::cout << "SKIPJACK" << std::endl;
    std::cout << "  Default keylength: " << SKIPJACK::DEFAULT_KEYLENGTH << std::endl;
    std::cout << "  Minimum keylength: " << SKIPJACK::MIN_KEYLENGTH << std::endl;
    std::cout << "  Maximum keylength: " << SKIPJACK::MAX_KEYLENGTH << std::endl;
    std::cout << "  Default blocksize: " << SKIPJACK::BLOCKSIZE << std::endl;

    return 0;
}

Running the program results in fixed sizes of 8 and 10.

$ ./test.exe
SKIPJACK
  Default keylength: 10
  Minimum keylength: 10
  Maximum keylength: 10
  Default blocksize: 8

The following program shows how to operate SKIPJACK in CBC mode using a pipeline.

AutoSeededRandomPool prng;

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

SecByteBlock iv(SKIPJACK::BLOCKSIZE);
prng.GenerateBlock(iv, iv.size());

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

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

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

    CBC_Mode< SKIPJACK >::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 ss1(plain, true,
        new StreamTransformationFilter(e,
            new StringSink(cipher)
        ) // StreamTransformationFilter
    ); // StringSource
}
catch(const CryptoPP::Exception& e)
{
    std::cerr << e.what() << std::endl;
    exit(1);
}

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

// Pretty print

encoded.clear();
StringSource ss2(key.begin(), key.size(), true,
    new HexEncoder(
        new StringSink(encoded)
    ) // HexEncoder
); // StringSource
std::cout << "key: " << encoded << std::endl;

encoded.clear();
StringSource ss3(iv.begin(), iv.size(), true,
    new HexEncoder(
        new StringSink(encoded)
    ) // HexEncoder
); // StringSource
std::cout << "iv: " << encoded << std::endl;

encoded.clear();
StringSource ss4(cipher, true,
    new HexEncoder(
        new StringSink(encoded)
    ) // HexEncoder
); // StringSource
std::cout << "cipher text: " << encoded << std::endl;

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

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

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

    std::cout << "recovered text: " << recovered << std::endl;
}
catch(const CryptoPP::Exception& e)
{
    std::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.

$ ./test.exe
plain text: CBC Mode Test
key: 2F00288D9F41E217E75D
iv: E2F9B312D8925F88
cipher text: 7B906BD1D6B94C3222DEA9E617D6094C
recovered text: CBC Mode Test

Test Vectors

There was some confusion about the Crypto++ SKIPJACK algorithm because it did not arrive at expected results from the article cited by Schneier. Also see Issue 824, SKIPJACK encryption gives wrong result.

Crypto++ conforms to NIST specifications, and passes the Known Answer Tests provided at SP800-17, Modes of Operation Validation System (MOVS): Requirements and Procedures (Table 6, pp. 140-42). Botan also arrives at the expected test vector results. The first several SKIPJACK/ECB test vectors are shown below.

Key: 80000000000000000000
Plaintext: 0000000000000000
Ciphertext: 7a00e494 41461f5a
#
Key: 40000000000000000000
Plaintext: 0000000000000000
Ciphertext: a14ff8bc d1bc9ef9
#
Key: 20000000000000000000
Plaintext: 0000000000000000
Ciphertext: d7e81038 5a42aaea

SKIPJACK/CBC test vectors are available at `TestVectors/skipjack.txt`. The collection include 1 block (8-bytes) through 10 blocks (80-bytes). The vectors were generated by Botan and cross-validated with Crypto++.

Downloads

No downloads.