SKIPJACK

From Crypto++ Wiki
Jump to: navigation, search

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

SKIPJACK
Documentation
#include <cryptopp/skipjack.h>

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.