Overview

Block Ciphers are supported via the GordianCipherFactory interface.

GordianKnot supports most Symmetric Block Ciphers available from BouncyCastle plus some additional ciphers.

A cipher for block encryption/decryption is created by specifying a GordianSymCipherSpec which comprises the GordianSymKeySpec (algorithm/blockSize/keySize) with the cipherMode and padding (if required). The cipher can be used in much the same way as a JCA Cipher, allowing init, update and finalise methods.

A cipher for blockCipher keyWrapping is created by specifying the symKey. The cipher allows init, secure and derive methods

A keyGenerator for a GordianSymKeySpec can be created, which can be used to generate random keys for the keySpec

JCA provides a subset of available algorithms as indicated

Key Generation

Algorithms are represented by GordianSymKeySpec. A GordianKeyGenerator is obtained via the keySpec, and then keys are generated by the generator.

Sample

                    /* Access factory */
                    final GordianFactory myBaseFactory = GordianGenerator.createFactory();
                    final GordianCipherFactory myCipherFactory = myBaseFactory.getCipherFactory();

                    /* Access keyGenerator */
                    final GordianSymKeySpec mySpec = GordianSymKeySpec.aes(GordianLength.LEN_256);
                    final GordianKeyGenerator<GordianSymKeySpec> myGenerator = myCipherFactory.getKeyGenerator(mySpec);
                    final GordianKey<GordianSymKeySpec> myKey = myGenerator.generateKey();
                

Algorithms

The following symKey algorithms are supported.

Algorithm BlockSize JCA 128 192 256 512 1024
AES 128 Y Y Y Y
Serpent 128 Y Y Y Y
TwoFish 128 Y Y Y Y
Camellia 128 Y Y Y Y
CAST6 128 Y Y Y Y
RC6 128 Y Y Y Y
ARIA 128 Y Y Y Y
Kalyna 128 Y Y Y
256 Y Y Y
Kuznyechik 128 Y Y
ThreeFish 256 Y Y Y Y
NoeKeon 64 Y Y
SM4 64 Y Y
SEED 64 Y Y
SKIPJACK 64 Y Y
BlowFish 64 Y Y Y Y
RC2 64 Y Y Y Y Y Y
DESede 64 Y Y Y
CAST5 64 Y Y
RC5 64 Y Y
128 Y Y
IDEA 64 Y Y
TEA 64 Y Y
XTEA 64 Y Y
Magma 64 Y Y
SHACAL2 256 Y Y Y
Speck 128 Y Y Y
Simon 128 Y Y Y
MARS 128 Y Y Y
Anubis 128 Y Y Y
LEA 128 Y Y Y

Cipher Usage

Cipher Algorithms are represented by GordianSymCipherSpec. A GordianSymCipher is obtained via the cipherSpec, and then messages are encrypted/decrypted by the cipher.

Sample

                    /* Access factory */
                    final GordianFactory myBaseFactory = GordianGenerator.createFactory();
                    final GordianCipherFactory myCipherFactory = myBaseFactory.getCipherFactory();

                    /* Create key */
                    final GordianSymKeySpec myKeySpec = GordianSymKeySpec.aes(GordianLength.LEN_256);
                    final GordianKeyGenerator<GordianSymKeySpec> myGenerator = myCipherFactory.getKeyGenerator(myKeySpec);
                    final GordianKey<GordianSymKeySpec> myKey = myGenerator.generateKey();

                    /* Create cipher */
                    final GordianSymCipherSpec myCipherSpec = GordianSymCipherSpec.cbc(myKeySpec, GordianPadding.PKCS7);
                    final GordianSymCipher myCipher = myCipherFactory.createSymKeyCipher(myCipherSpec);

                    /* Encrypt message with random nonce */
                    GordianCipherParameters myParams = GordianCipherParameters.keyWithRandomNonce(myKey);
                    myCipher.initForEncrypt(myParams);
                    final byte[] myMessage = ...
                    int myOutLen = myCipher.getOutputLength(myMessage.length);
                    final byte[] myEncrypted = new byte[myOutLen];
                    int myProcessed = myCipher.update(myMessage, 0, myMessage.length, myEncrypted);
                    myCipher.finish(myEncrypted, myProcessed);

                    /* Decrypt message */
                    myParams = GordianCipherParameters.keyWithNonce(myKey, myCipher.getNonce());
                    myCipher.initForDecrypt(myParams);
                    myOutLen = myCipher.getOutputLength(myEncrypted.length);
                    final byte[] myResult = new byte[myOutLen];
                    myProcessed = myCipher.update(myEncrypted, 0, myEncrypted.length, myResult);
                    myCipher.finish(myResult, myProcessed);
                

Cipher Modes

The following modes can be used

Mode JCA Notes
ECB Y
CBC Y JCA does not support for Kuznyechik
G3413CBC Y Only available for Kuznyechik
SIC Y
KCTR Y Only available for Kalyna
G3413CTR Y Only available for Kuznyechik
OFB Y Jca does not support for Magma and Kuznyechik
GOFB Only available for Magma
G3413OFB Y Only available for Kuznyechik
CFB Y Jca does not support for Magma and Kuznyechik
GCFB Only available for Magma
G3413CFB Y Only available for Kuznyechik
CCM Y Jca does not support for Kalyna
KCCM Only available for Kalyna
GCM Y Jca does not support for Kalyna
KGCM Only available for Kalyna
EAX Y
OCB Y JCA does not support for Kuznyechik or Kalyna
GCMSIV Only available for 128-bit/256-bit keys and 128-bit blocks

Padding

The following paddings can be used for ECB and CBC modes

Padding JCA Notes
CTS Y
ISO7816-4 Y
PKCS7 Y
X9.63 Y
TBC Y
NONE Y Implicitly used for modes other than ECB/CBC

Key Wrapping

Key Wrapping is performed by GordianKnot using a variant of the AES Key Wrapping algorithm specified in RFC 5649

The differences are necessary to enable support of ciphers that do not have the standard blockSize of 128 bits, since RFC 5649 assumes a 128 bit blockSize.

  1. For blockSizes of 256 bits, the 32-bit Integrity Vector of 0xA65959A6 is expanded to the 96-bit 0xA65959A6A65959A6A65959A6 so that when combined with the 32-bit dataLen of the wrapped data it comprises the half-block needed for the wrapping algorithm. This method can be extended to support any block size >= 128.
  2. For blockSizes of 64, the Integrity Vector using the above adjustment becomes zero length, which is not very useful. In this case, we retain the standard 32-bit Integrity Vector of 0xA65959A6 and prefix the 32-bit dataLen to the data to be wrapped.

In addition, a block of random data is inserted immediately prior to the data to be wrapped.

Sample

                    /* Access factory */
                    final GordianFactory myBaseFactory = GordianGenerator.createFactory();
                    final GordianCipherFactory myCipherFactory = myBaseFactory.getCipherFactory();

                    /* Create keys */
                    final GordianSymKeySpec myKeySpec = GordianSymKeySpec.aes(GordianLength.LEN_256);
                    final GordianKeyGenerator<GordianSymKeySpec> myGenerator = myCipherFactory.getKeyGenerator(myKeySpec);
                    final GordianKey<GordianSymKeySpec> myKey = myGenerator.generateKey();
                    final GordianKey<GordianSymKeySpec> myKeyToWrap = myGenerator.generateKey();

                    /* Create keyWrapper */
                    final GordianKeyWrapper myWrapper = myCipherFactory.createSymKeyCipher(myKey);

                    /* Secure key */
                    final byte[] myWrapped = myWrapper.secureKey(myKeyToWrap);

                    /* Derive Key */
                    final GordianKey<GordianSymKeySpec> myResult = myWrapper.deriveKey(myWrapped, myKeySpec);