
4 changed files with 0 additions and 495 deletions
@ -1,348 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Freie Universität Berlin, Computer Systems & Telematics |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup sys_crypto |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief implementation of the SkipJack Cipher-Algorithm |
||||
* |
||||
* @author Freie Universitaet Berlin, Computer Systems & Telematics |
||||
* @author Nicolai Schmittberger <nicolai.schmittberger@fu-berlin.de> |
||||
* @author Zakaria Kasmi <zkasmi@inf.fu-berlin.de> |
||||
* @author Naveen Sastry |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
/*
|
||||
* From the NIST description of SkipJack. |
||||
*/ |
||||
// our context: we just expand the key to 20 bytes.
|
||||
//
|
||||
// we have two options for the expansion:
|
||||
// 1. no expansion. advantage: 10byte context. disadvantage: mucks up
|
||||
// the G box code with ifs / mods. Alternatively adds lots of code and
|
||||
// muckiness.
|
||||
// 2. expand key to 128 bytes. Makes G boxes easy to write, and minimal
|
||||
// code expansion. disadvantage: wasted memory
|
||||
// 3. expand key to 20 bytes. G boxes still simple, the encode and decode
|
||||
// functions are a little more complicated, but still more or less
|
||||
// managable. this is what we've implemented.
|
||||
|
||||
#include <stdio.h> |
||||
#include <stdarg.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <stdint.h> |
||||
#include "crypto/ciphers.h" |
||||
#include "crypto/skipjack.h" |
||||
|
||||
|
||||
/**
|
||||
* @brief Define a fixed block size of 8 bytes |
||||
*/ |
||||
#define BLOCK_SIZE (8U) |
||||
|
||||
/**
|
||||
* @brief Interface to the skipjack cipher |
||||
*/ |
||||
static const cipher_interface_t skipjack_interface = { |
||||
BLOCK_SIZE, |
||||
CIPHERS_MAX_KEY_SIZE, |
||||
skipjack_init, |
||||
skipjack_encrypt, |
||||
skipjack_decrypt |
||||
}; |
||||
const cipher_id_t CIPHER_SKIPJACK = &skipjack_interface; |
||||
|
||||
// F-BOX
|
||||
// It can live in either RAM (faster access) or program memory (save ram,
|
||||
// but slower access). The type CRYPTO_TABLE_TYPE, defined in crypto.h
|
||||
// defines where we drop the table and how we access it. This is necessary
|
||||
// to compile for the PC target since it doesn't support tables in
|
||||
// program memory the same way.
|
||||
static const uint8_t SJ_F[] /*__attribute__((C))*/ = { |
||||
0xA3, 0xD7, 0x09, 0x83, 0xF8, 0x48, 0xF6, 0xF4, 0xB3, 0x21, 0x15, 0x78, |
||||
0x99, 0xB1, 0xAF, 0xF9, 0xE7, 0x2D, 0x4D, 0x8A, 0xCE, 0x4C, 0xCA, 0x2E, |
||||
0x52, 0x95, 0xD9, 0x1E, 0x4E, 0x38, 0x44, 0x28, 0x0A, 0xDF, 0x02, 0xA0, |
||||
0x17, 0xF1, 0x60, 0x68, 0x12, 0xB7, 0x7A, 0xC3, 0xE9, 0xFA, 0x3D, 0x53, |
||||
0x96, 0x84, 0x6B, 0xBA, 0xF2, 0x63, 0x9A, 0x19, 0x7C, 0xAE, 0xE5, 0xF5, |
||||
0xF7, 0x16, 0x6A, 0xA2, 0x39, 0xB6, 0x7B, 0x0F, 0xC1, 0x93, 0x81, 0x1B, |
||||
0xEE, 0xB4, 0x1A, 0xEA, 0xD0, 0x91, 0x2F, 0xB8, 0x55, 0xB9, 0xDA, 0x85, |
||||
0x3F, 0x41, 0xBF, 0xE0, 0x5A, 0x58, 0x80, 0x5F, 0x66, 0x0B, 0xD8, 0x90, |
||||
0x35, 0xD5, 0xC0, 0xA7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56, |
||||
0x6D, 0x98, 0x9B, 0x76, 0x97, 0xFC, 0xB2, 0xC2, 0xB0, 0xFE, 0xDB, 0x20, |
||||
0xE1, 0xEB, 0xD6, 0xE4, 0xDD, 0x47, 0x4A, 0x1D, 0x42, 0xED, 0x9E, 0x6E, |
||||
0x49, 0x3C, 0xCD, 0x43, 0x27, 0xD2, 0x07, 0xD4, 0xDE, 0xC7, 0x67, 0x18, |
||||
0x89, 0xCB, 0x30, 0x1F, 0x8D, 0xC6, 0x8F, 0xAA, 0xC8, 0x74, 0xDC, 0xC9, |
||||
0x5D, 0x5C, 0x31, 0xA4, 0x70, 0x88, 0x61, 0x2C, 0x9F, 0x0D, 0x2B, 0x87, |
||||
0x50, 0x82, 0x54, 0x64, 0x26, 0x7D, 0x03, 0x40, 0x34, 0x4B, 0x1C, 0x73, |
||||
0xD1, 0xC4, 0xFD, 0x3B, 0xCC, 0xFB, 0x7F, 0xAB, 0xE6, 0x3E, 0x5B, 0xA5, |
||||
0xAD, 0x04, 0x23, 0x9C, 0x14, 0x51, 0x22, 0xF0, 0x29, 0x79, 0x71, 0x7E, |
||||
0xFF, 0x8C, 0x0E, 0xE2, 0x0C, 0xEF, 0xBC, 0x72, 0x75, 0x6F, 0x37, 0xA1, |
||||
0xEC, 0xD3, 0x8E, 0x62, 0x8B, 0x86, 0x10, 0xE8, 0x08, 0x77, 0x11, 0xBE, |
||||
0x92, 0x4F, 0x24, 0xC5, 0x32, 0x36, 0x9D, 0xCF, 0xF3, 0xA6, 0xBB, 0xAC, |
||||
0x5E, 0x6C, 0xA9, 0x13, 0x57, 0x25, 0xB5, 0xE3, 0xBD, 0xA8, 0x3A, 0x01, |
||||
0x05, 0x59, 0x2A, 0x46 |
||||
}; |
||||
|
||||
|
||||
/**
|
||||
* @brief convert 2x uint8_t to uint16_t |
||||
* |
||||
* @param c pointer to the 2x uint8_t input |
||||
* @param s pointer to the resulting uint16_t |
||||
* |
||||
*/ |
||||
static void c2sM(const uint8_t *c, uint16_t *s) |
||||
{ |
||||
memcpy(s, c, sizeof(uint16_t)); |
||||
return; |
||||
} |
||||
|
||||
/**
|
||||
* @brief convert one uint16_t to 2x uint8_t |
||||
* |
||||
* @param s pointer to the uint16_t input |
||||
* @param c pointer to the first resulting uint8_ts |
||||
*/ |
||||
static void s2cM(const uint16_t s, uint8_t *c) |
||||
{ |
||||
memcpy(c, &s, sizeof(uint16_t)); |
||||
return; |
||||
} |
||||
|
||||
|
||||
int skipjack_encrypt(const cipher_context_t *context, const uint8_t *plainBlock, |
||||
uint8_t *cipherBlock) |
||||
{ |
||||
|
||||
// prologue 10 pushs = 20 cycles
|
||||
/*register*/ uint8_t counter = 1; |
||||
cipher_context_t *skipjack_context = (cipher_context_t *)context->context; |
||||
/*register*/ uint8_t *skey = skipjack_context->context; |
||||
|
||||
/*register*/ uint16_t w1, w2, w3, w4, tmp; |
||||
/*register*/ uint8_t bLeft, bRight; |
||||
|
||||
//dumpBuffer("SkipJack.encrypt: plainBlock", plainBlock, 8);
|
||||
|
||||
c2sM(plainBlock, &w1); |
||||
plainBlock += 2; |
||||
c2sM(plainBlock, &w2); |
||||
plainBlock += 2; |
||||
c2sM(plainBlock, &w3); |
||||
plainBlock += 2; |
||||
c2sM(plainBlock, &w4); |
||||
plainBlock += 2; |
||||
|
||||
/*
|
||||
* code if we had expanded key to 128 bytes. this is what the code below |
||||
* does, but after every 5 operations, it resets the where we are |
||||
* in the key back to the beginning of the skey. so our loops end up |
||||
* looking a little funny. |
||||
* |
||||
* while (counter < 9) |
||||
* RULE_A(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight ); |
||||
* while (counter < 17) |
||||
* RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight ); |
||||
* while (counter < 25) |
||||
* RULE_A(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight ); |
||||
* while (counter < 33) |
||||
* RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight ); |
||||
*/ |
||||
|
||||
while (counter < 6) { // 5x
|
||||
RULE_A(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
skey = skipjack_context->context; |
||||
|
||||
while (counter < 9) { // 3x
|
||||
RULE_A(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
while (counter < 11) { // 2x
|
||||
RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
skey = skipjack_context->context; |
||||
|
||||
while (counter < 16) { // 5x
|
||||
RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
skey = skipjack_context->context; |
||||
// 1x
|
||||
RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
|
||||
while (counter < 21) { // 4x
|
||||
RULE_A(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
skey = skipjack_context->context; |
||||
|
||||
while (counter < 25) { // 4x
|
||||
RULE_A(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
// 1x
|
||||
RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
skey = skipjack_context->context; |
||||
|
||||
while (counter < 31) { // 5x
|
||||
RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
skey = skipjack_context->context; |
||||
|
||||
while (counter < 33) { // 2x
|
||||
RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
s2cM(w1, cipherBlock); |
||||
cipherBlock += 2; |
||||
s2cM(w2, cipherBlock); |
||||
cipherBlock += 2; |
||||
s2cM(w3, cipherBlock); |
||||
cipherBlock += 2; |
||||
s2cM(w4, cipherBlock); |
||||
/* cppcheck: may introduce timing bias if left out */ |
||||
/* cppcheck-suppress uselessAssignmentPtrArg */ |
||||
cipherBlock += 2; |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
|
||||
int skipjack_decrypt(const cipher_context_t *context, const uint8_t *cipherBlock, |
||||
uint8_t *plainBlock) |
||||
{ |
||||
/*register*/ uint8_t counter = 32; |
||||
cipher_context_t *skipjack_context = (cipher_context_t *)context->context; |
||||
/*register*/ uint8_t *skey = skipjack_context->context + 4; |
||||
/*register*/ uint16_t w1, w2, w3, w4, tmp; |
||||
/*register*/ uint8_t bLeft, bRight; |
||||
|
||||
//dumpBuffer("SkipJack.decrypt: cipherBlock", cipherBlock, 8);
|
||||
|
||||
c2sM(cipherBlock, &w1); |
||||
cipherBlock += 2; |
||||
c2sM(cipherBlock, &w2); |
||||
cipherBlock += 2; |
||||
c2sM(cipherBlock, &w3); |
||||
cipherBlock += 2; |
||||
c2sM(cipherBlock, &w4); |
||||
|
||||
/*
|
||||
// code if we had expanded key to 128 bytes. this is what the code below
|
||||
// does, but after every 5 operations, it resets the where we are
|
||||
// in the key back to the beginning of the skey. so our loops end up
|
||||
// looking a little funny.
|
||||
|
||||
while (counter > 24) |
||||
RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight ); |
||||
while (counter > 16) |
||||
RULE_A_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight ); |
||||
while (counter > 8) |
||||
RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight ); |
||||
while (counter > 0) |
||||
RULE_A_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight ); |
||||
*/ |
||||
|
||||
while (counter > 30) { //2x
|
||||
RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
skey = skipjack_context->context + 16; |
||||
|
||||
while (counter > 25) { //5x
|
||||
RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
skey = skipjack_context->context + 16; |
||||
//1x
|
||||
RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
|
||||
while (counter > 20) { //4x
|
||||
RULE_A_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
skey = skipjack_context->context + 16; |
||||
|
||||
while (counter > 16) { //4x
|
||||
RULE_A_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
//1x
|
||||
RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
skey = skipjack_context->context + 16; |
||||
|
||||
while (counter > 10) { //5x
|
||||
RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
skey = skipjack_context->context + 16; |
||||
|
||||
while (counter > 8) { // 2x
|
||||
RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
while (counter > 5) { // 3x
|
||||
RULE_A_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
skey = skipjack_context->context + 16; |
||||
|
||||
while (counter > 0) { // 5x
|
||||
RULE_A_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight); |
||||
} |
||||
|
||||
s2cM(w1, plainBlock); |
||||
plainBlock += 2; |
||||
s2cM(w2, plainBlock); |
||||
plainBlock += 2; |
||||
s2cM(w3, plainBlock); |
||||
plainBlock += 2; |
||||
s2cM(w4, plainBlock); |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
|
||||
int skipjack_init(cipher_context_t *context, const uint8_t *key, uint8_t keysize) |
||||
{ |
||||
int i = 0; |
||||
|
||||
// Make sure that context is large enough. If this is not the case,
|
||||
// you should build with -DSKIPJACK.
|
||||
if(CIPHER_MAX_CONTEXT_SIZE < SKIPJACK_CONTEXT_SIZE) { |
||||
return 0; |
||||
} |
||||
|
||||
cipher_context_t *skipjack_context = (cipher_context_t *)context->context; |
||||
uint8_t *skey = skipjack_context->context; |
||||
|
||||
// for keys which are smaller than 160 bits, concatenate until they reach
|
||||
// 160 bits in size. Note that key expansion is just concatenation.
|
||||
if (keysize < CIPHERS_MAX_KEY_SIZE) { |
||||
//fill up by concatenating key to as long as needed
|
||||
for (i = 0; i < CIPHERS_MAX_KEY_SIZE; i++) { |
||||
skey[i] = key[(i % keysize)]; |
||||
} |
||||
} |
||||
else { |
||||
for (i = 0; i < CIPHERS_MAX_KEY_SIZE; i++) { |
||||
skey[i] = key[i]; |
||||
} |
||||
} |
||||
|
||||
return 1; |
||||
} |
@ -1,141 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Freie Universität Berlin, Computer Systems & Telematics |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup sys_crypto |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Headers for the implementation of the SkipJack cipher-algorithm |
||||
* |
||||
* @author Freie Universitaet Berlin, Computer Systems & Telematics |
||||
* @author Nicolai Schmittberger <nicolai.schmittberger@fu-berlin.de> |
||||
* @author Zakaria Kasmi <zkasmi@inf.fu-berlin.de> |
||||
*/ |
||||
|
||||
#ifndef SKIPJACK_H_ |
||||
#define SKIPJACK_H_ |
||||
|
||||
#include "crypto/ciphers.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#define F(addr) /*CRYPTO_TABLE_ACCESS( &SJ_F[addr])*/ (SJ_F[addr]) |
||||
|
||||
// G-Permutation: 4 round feistel structure
|
||||
#define G(key, b, bLeft, bRight) \ |
||||
( \
|
||||
bLeft = b, \
|
||||
bRight = (b >> 8), \
|
||||
bLeft ^= F(bRight ^ key[0]), \
|
||||
bRight ^= F(bLeft ^ key[1]), \
|
||||
bLeft ^= F(bRight ^ key[2]), \
|
||||
bRight ^= F(bLeft ^ key[3]), \
|
||||
((bRight << 8) | bLeft)) |
||||
|
||||
#define G_INV(key, b, bLeft, bRight) \ |
||||
( bLeft = b, \
|
||||
bRight = (b >> 8), \
|
||||
bRight ^= F(bLeft ^ key[3]), \
|
||||
bLeft ^= F(bRight ^ key[2]), \
|
||||
bRight ^= F(bLeft ^ key[1]), \
|
||||
bLeft ^= F(bRight ^ key[0]), \
|
||||
((bRight << 8) | bLeft)) |
||||
|
||||
// A-RULE:
|
||||
#define RULE_A(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight ) { \ |
||||
tmp = w4; \
|
||||
w4 = w3; \
|
||||
w3 = w2; \
|
||||
w2 = G(skey, w1, bLeft, bRight); \
|
||||
w1 = ((tmp ^ w2) ^ counter); \
|
||||
counter++; \
|
||||
skey += 4; } |
||||
|
||||
#define RULE_A_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight) { \ |
||||
tmp = w4; \
|
||||
w4 = (w1 ^ w2 ^ counter); \
|
||||
w1 = G_INV(skey, w2, bLeft, bRight); \
|
||||
w2 = w3; \
|
||||
w3 = tmp; \
|
||||
counter--; \
|
||||
skey -= 4; } \
|
||||
|
||||
// B-RULE:
|
||||
#define RULE_B(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight ) { \ |
||||
tmp = w1; \
|
||||
w1 = w4; \
|
||||
w4 = w3; \
|
||||
w3 = (tmp ^ w2 ^ counter); \
|
||||
w2 = G(skey, tmp, bLeft, bRight); \
|
||||
counter++; \
|
||||
skey += 4; } |
||||
|
||||
#define RULE_B_INV(skey, w1, w2, w3, w4, counter, tmp, bLeft, bRight ) { \ |
||||
tmp = w1; \
|
||||
w1 = G_INV(skey, w2, bLeft, bRight); \
|
||||
w2 = (w1 ^ w3 ^ counter); \
|
||||
w3 = w4; \
|
||||
w4 = tmp; \
|
||||
counter--; \
|
||||
skey -= 4; } |
||||
|
||||
/** 2 times keysize. makes unrolling keystream easier / efficient */ |
||||
#define SKIPJACK_CONTEXT_SIZE 20 |
||||
|
||||
/**
|
||||
* @brief Initialize the SkipJack-BlockCipher context. |
||||
* |
||||
* @param context structure to hold the opaque data from this |
||||
* initialization call. It should be passed to future |
||||
* invocations of this module which use this particular |
||||
* key. |
||||
* @param keySize key size in bytes |
||||
* @param key pointer to the key |
||||
* |
||||
* @return Whether initialization was successful. The command may be |
||||
* unsuccessful if the key size is not valid. |
||||
*/ |
||||
int skipjack_init(cipher_context_t *context, const uint8_t *key, uint8_t keySize); |
||||
|
||||
/**
|
||||
* @brief Encrypts a single block (of blockSize) using the passed context. |
||||
* |
||||
* @param context holds the module specific opaque data related to the |
||||
* key (perhaps key expansions). |
||||
* @param plainBlock a plaintext block of blockSize |
||||
* @param cipherBlock the resulting ciphertext block of blockSize |
||||
* |
||||
* @return Whether the encryption was successful. Possible failure reasons |
||||
* include not calling init(). |
||||
*/ |
||||
int skipjack_encrypt(const cipher_context_t *context, const uint8_t *plainBlock, |
||||
uint8_t *cipherBlock); |
||||
|
||||
/**
|
||||
* @brief Decrypts a single block (of blockSize) using the passed context. |
||||
* |
||||
* @param context holds the module specific opaque data related to the |
||||
* key (perhaps key expansions). |
||||
* @param cipherBlock a ciphertext block of blockSize |
||||
* @param plainBlock the resulting plaintext block of blockSize |
||||
* |
||||
* @return Whether the decryption was successful. Possible failure reasons |
||||
* include not calling init() |
||||
*/ |
||||
int skipjack_decrypt(const cipher_context_t *context, const uint8_t *cipherBlock, |
||||
uint8_t *plainBlock); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
/** @} */ |
||||
#endif /* SKIPJACK_H_ */ |
Loading…
Reference in new issue