Threefish

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

Threefish is a tweakable block cipher for the Skein hash function designed by Bruce Schneier, Niels Ferguson, Stefan Lucks, Doug Whiting, Mihir Bellare, Tadayoshi Kohno, Jon Callas, and Jesse Walker. Threefish is hardened against timing attacks by avoiding S-Boxes and table lookups.

Crypto++ added the block cipher prior to the 6.0 release at Commit 8c34a5f7f5d1. Also see Issue 422, Add Threefish block cipher. The initial port used variable block sizes, but they were a little harder to use and subsequently removed. Variable block sizes were removed in favor of fixed block sizes at Commit b9bd51f7a61b1e1a. Also see Issue 535, Remove variable block size support for block ciphers.

As of this writing there are several open tasks for large block ciphers. The last prominent issue is, what to do with GCM mode. NIST only approves AES for GCM, so larger polynomials are missing for block sizes of 256-bit, 512-bit and 1024-bit. We believe we have the correct polynomials, but we need to modify GCM. Also Issue 423, Polynomials for CMAC and GCM mode.

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.

Threefish classes

Threefish provides three classes depending on the block size. The classes are Threefish256, Threefish512 and Threefish1024. The trailing number indicates block size, not the key size.

You use the classes just like any other block cipher.

Algorithm Name

If you call StaticAlgorithmName then the function will return the full name "Threefish-<block size>(<key length>)". In the case of Threefish the three algorithms names are Threefish-256(256), Threefish-512(512) and Threefish-1024(1024).

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[])
{
    Threefish256::Encryption threefish;

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

    byte key[Threefish256::DEFAULT_KEYLENGTH];
    threefish.SetKey(key, sizeof(key));

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

    return 0;
}

The program results in the following output.

$ ./test.exe
StaticAlgorithmName: Threefish-256(256)
AlgorithmName (unkeyed): Threefish-256(256)
AlgorithmName (keyed): Threefish-256(256)

Modes of Operation

Threefish is considered a "wide block" block cipher because it uses block sizes greater than 128-bits. There are pain points when using wide block ciphers, like incomplete support for some modes of operation. The problem is largely due to missing specifications for the wider block sizes, which means we don't know how to implement an algorithm in a standard way. A side effect is, no specifications lead to missing test vectors.

Examples of missing specifications include missing polynomials for CMAC and GCM modes of operation. It is not enough to simply use a low weight polynomial since there can be multiple primitive polynomials available. We are tracking the missing polynomials at Issue 423, Polynomials for CMAC and GCM mode.

Another example of a missing specification is counter mode operations. The mode could be as simple as using a larger counter, or it could use a zero-extended 128-bit counter. Sometimes the result of counter mode operation is reduced by a primitive polynomial, so it can also suffer missing polynomials detailed in CMAC and GCM.

Yet another example is CCM, EAX and GCM are authenticated encryption modes of operation. The modes produce an authentication tag and the tag has traditionally been the size of the block. In the case of AES, Camellia that's 128-bits and it is sufficient to authenticate the data. In the case of wide blocks we don't know if tags should be extended accordingly. As we understand the latest revision to OCB mode, the tags are not extended.

At this point in time we believe the status of wide block modes of operation are:

  • CMAC - may work, but we don't have test vectors
  • CBC - probably works, we had Kalyna test vectors
  • CTR - probably works, we had Kalyna test vectors
  • EAX - may work, but we don't have test vectors
  • GCM - does not work, we don't have an implementation
  • CCM - probably does not work, we don't have a specification
  • OCB - in progress, not ready for production
  • Others - modes like OFB and CFB probably work

In a few places we said, "probably works, we had Kalyna test vectors". There is a danger we cannot make the leap because Kalyna uses operations specified in DSTU, which is a Ukranian national standard. The standard may be different than what ISO/IEC, NESSIE, NIST or the IETF eventually produce.

Sample Programs

There are three sample programs. The first shows Threefish 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.

Key and Block sizes

Below is the first program. It prints key and block size for the cipher.

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

    std::cout << "Threefish512" << std::endl;
    std::cout << "Default keylength: " << Threefish512::DEFAULT_KEYLENGTH << std::endl;
    std::cout << "Minimum keylength: " << Threefish512::MIN_KEYLENGTH << std::endl;
    std::cout << "Maximum keylength: " << Threefish512::MAX_KEYLENGTH << std::endl;
    std::cout << "Default blocksize: " << Threefish512::BLOCKSIZE << std::endl;

    std::cout << "Threefish1024" << std::endl;
    std::cout << "Default keylength: " << Threefish1024::DEFAULT_KEYLENGTH << std::endl;
    std::cout << "Minimum keylength: " << Threefish1024::MIN_KEYLENGTH << std::endl;
    std::cout << "Maximum keylength: " << Threefish1024::MAX_KEYLENGTH << std::endl;
    std::cout << "Default blocksize: " << Threefish1024::BLOCKSIZE << std::endl;

    return 0;
}

Running the program results in a range of 32 to 128 bytes.

$ ./test.exe
Threefish256
Default keylength: 32
Minimum keylength: 32
Maximum keylength: 32
Default blocksize: 32
Threefish512
Default keylength: 64
Minimum keylength: 64
Maximum keylength: 64
Default blocksize: 64
Threefish1024
Default keylength: 128
Minimum keylength: 128
Maximum keylength: 128
Default blocksize: 128

Downloads

No downloads.