Mercurial > pt1.oyama
diff arib25v021/arib25/src/multi2.c @ 0:67e8eca28a80
initial import
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Mon, 16 Feb 2009 15:41:49 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arib25v021/arib25/src/multi2.c Mon Feb 16 15:41:49 2009 +0900 @@ -0,0 +1,527 @@ +#include <stdlib.h> +#include <string.h> + +#include "multi2.h" +#include "multi2_error_code.h" + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + inline functions + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +static __inline uint8_t *load_be_uint32(uint32_t *dst, uint8_t *src) +{ + *dst = ((src[0]<<24)|(src[1]<<16)|(src[2]<<8)|src[3]); + return src+4; +} + +static __inline uint8_t *save_be_uint32(uint8_t *dst, uint32_t src) +{ + dst[0] = (uint8_t)((src>>24) & 0xff); + dst[1] = (uint8_t)((src>>16) & 0xff); + dst[2] = (uint8_t)((src>> 8) & 0xff); + dst[3] = (uint8_t)( src & 0xff); + return dst+4; +} + +static __inline uint32_t left_rotate_uint32(uint32_t val, uint32_t count) +{ + return ((val << count) | (val >> (32-count))); +} + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + inner structures + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +typedef struct { + uint32_t key[8]; +} CORE_PARAM; + +typedef struct { + uint32_t l; + uint32_t r; +} CORE_DATA; + +typedef struct { + + int32_t ref_count; + + CORE_DATA cbc_init; + + CORE_PARAM sys; + CORE_DATA scr[2]; /* 0: odd, 1: even */ + CORE_PARAM wrk[2]; /* 0: odd, 1: even */ + + uint32_t round; + uint32_t state; + +} MULTI2_PRIVATE_DATA; + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + constant values + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +#define MULTI2_STATE_CBC_INIT_SET (0x0001) +#define MULTI2_STATE_SYSTEM_KEY_SET (0x0002) +#define MULTI2_STATE_SCRAMBLE_KEY_SET (0x0004) + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + function prottypes (interface method) + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +static void release_multi2(void *m2); +static int add_ref_multi2(void *m2); +static int set_round_multi2(void *m2, int32_t val); +static int set_system_key_multi2(void *m2, uint8_t *val); +static int set_init_cbc_multi2(void *m2, uint8_t *val); +static int set_scramble_key_multi2(void *m2, uint8_t *val); +static int clear_scramble_key_multi2(void *m2); +static int encrypt_multi2(void *m2, int32_t type, uint8_t *buf, int32_t size); +static int decrypt_multi2(void *m2, int32_t type, uint8_t *buf, int32_t size); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + global function implementation + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +MULTI2 *create_multi2() +{ + int n; + + MULTI2 *r; + MULTI2_PRIVATE_DATA *prv; + + n = sizeof(MULTI2_PRIVATE_DATA); + n += sizeof(MULTI2); + + prv = (MULTI2_PRIVATE_DATA *)calloc(1, n); + if(prv == NULL){ + return NULL; + } + + r = (MULTI2 *)(prv+1); + r->private_data = prv; + + prv->ref_count = 1; + prv->round = 4; + + r->release = release_multi2; + r->add_ref = add_ref_multi2; + r->set_round = set_round_multi2; + r->set_system_key = set_system_key_multi2; + r->set_init_cbc = set_init_cbc_multi2; + r->set_scramble_key = set_scramble_key_multi2; + r->clear_scramble_key = clear_scramble_key_multi2; + r->encrypt = encrypt_multi2; + r->decrypt = decrypt_multi2; + + return r; +} + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + function prottypes (private method) + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +static MULTI2_PRIVATE_DATA *private_data(void *m2); + +static void core_schedule(CORE_PARAM *work, CORE_PARAM *skey, CORE_DATA *dkey); + +static void core_encrypt(CORE_DATA *dst, CORE_DATA *src, CORE_PARAM *w, int32_t round); +static void core_decrypt(CORE_DATA *dst, CORE_DATA *src, CORE_PARAM *w, int32_t round); + +static void core_pi1(CORE_DATA *dst, CORE_DATA *src); +static void core_pi2(CORE_DATA *dst, CORE_DATA *src, uint32_t a); +static void core_pi3(CORE_DATA *dst, CORE_DATA *src, uint32_t a, uint32_t b); +static void core_pi4(CORE_DATA *dst, CORE_DATA *src, uint32_t a); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + interface method implementation + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +static void release_multi2(void *m2) +{ + MULTI2_PRIVATE_DATA *prv; + + prv = private_data(m2); + if(prv == NULL){ + /* do nothing */ + return; + } + + prv->ref_count -= 1; + if(prv->ref_count == 0){ + free(prv); + } +} + +static int add_ref_multi2(void *m2) +{ + MULTI2_PRIVATE_DATA *prv; + + prv = private_data(m2); + if(prv == NULL){ + return MULTI2_ERROR_INVALID_PARAMETER; + } + + prv->ref_count += 1; + + return 0; +} + +static int set_round_multi2(void *m2, int32_t val) +{ + MULTI2_PRIVATE_DATA *prv; + + prv = private_data(m2); + if(prv == NULL){ + /* do nothing */ + return MULTI2_ERROR_INVALID_PARAMETER; + } + + prv->round = val; + + return 0; +} + +static int set_system_key_multi2(void *m2, uint8_t *val) +{ + int i; + uint8_t *p; + + MULTI2_PRIVATE_DATA *prv; + + prv = private_data(m2); + if( (prv == NULL) || (val == NULL) ){ + return MULTI2_ERROR_INVALID_PARAMETER; + } + + p = val; + for(i=0;i<8;i++){ + p = load_be_uint32(prv->sys.key+i, p); + } + + prv->state |= MULTI2_STATE_SYSTEM_KEY_SET; + + return 0; +} + +static int set_init_cbc_multi2(void *m2, uint8_t *val) +{ + uint8_t *p; + + MULTI2_PRIVATE_DATA *prv; + + prv = private_data(m2); + if( (prv == NULL) || (val == NULL) ){ + return MULTI2_ERROR_INVALID_PARAMETER; + } + + p = val; + + p = load_be_uint32(&(prv->cbc_init.l), p); + p = load_be_uint32(&(prv->cbc_init.r), p); + + prv->state |= MULTI2_STATE_CBC_INIT_SET; + + return 0; +} + +static int set_scramble_key_multi2(void *m2, uint8_t *val) +{ + uint8_t *p; + + MULTI2_PRIVATE_DATA *prv; + + prv = private_data(m2); + if( (prv == NULL) || (val == NULL) ){ + return MULTI2_ERROR_INVALID_PARAMETER; + } + + p = val; + + p = load_be_uint32(&(prv->scr[0].l), p); + p = load_be_uint32(&(prv->scr[0].r), p); + p = load_be_uint32(&(prv->scr[1].l), p); + p = load_be_uint32(&(prv->scr[1].r), p); + + core_schedule(prv->wrk+0, &(prv->sys), prv->scr+0); + core_schedule(prv->wrk+1, &(prv->sys), prv->scr+1); + + prv->state |= MULTI2_STATE_SCRAMBLE_KEY_SET; + + return 0; +} + +static int clear_scramble_key_multi2(void *m2) +{ + MULTI2_PRIVATE_DATA *prv; + + prv = private_data(m2); + if(prv == NULL){ + return MULTI2_ERROR_INVALID_PARAMETER; + } + + memset(prv->scr, 0, sizeof(prv->scr)); + memset(prv->wrk, 0, sizeof(prv->wrk)); + + prv->state &= (~MULTI2_STATE_SCRAMBLE_KEY_SET); + + return 0; +} + +static int encrypt_multi2(void *m2, int32_t type, uint8_t *buf, int32_t size) +{ + CORE_DATA src,dst; + CORE_PARAM *prm; + + uint8_t *p; + + MULTI2_PRIVATE_DATA *prv; + + prv = private_data(m2); + if( (prv == NULL) || (buf == NULL) || (size < 1) ){ + return MULTI2_ERROR_INVALID_PARAMETER; + } + + if(prv->state != (MULTI2_STATE_CBC_INIT_SET|MULTI2_STATE_SYSTEM_KEY_SET|MULTI2_STATE_SCRAMBLE_KEY_SET)){ + if( (prv->state & MULTI2_STATE_CBC_INIT_SET) == 0 ){ + return MULTI2_ERROR_UNSET_CBC_INIT; + } + if( (prv->state & MULTI2_STATE_SYSTEM_KEY_SET) == 0 ){ + return MULTI2_ERROR_UNSET_SYSTEM_KEY; + } + if( (prv->state & MULTI2_STATE_SCRAMBLE_KEY_SET) == 0 ){ + return MULTI2_ERROR_UNSET_SCRAMBLE_KEY; + } + } + + if(type == 0x02){ + prm = prv->wrk+1; + }else{ + prm = prv->wrk+0; + } + + dst.l = prv->cbc_init.l; + dst.r = prv->cbc_init.r; + + p = buf; + while(size >= 8){ + load_be_uint32(&(src.l), p+0); + load_be_uint32(&(src.r), p+4); + src.l = src.l ^ dst.l; + src.r = src.r ^ dst.r; + core_encrypt(&dst, &src, prm, prv->round); + p = save_be_uint32(p, dst.l); + p = save_be_uint32(p, dst.r); + size -= 8; + } + + if(size > 0){ + int i; + uint8_t tmp[8]; + + src.l = dst.l; + src.r = dst.r; + core_encrypt(&dst, &src, prm, prv->round); + save_be_uint32(tmp+0, dst.l); + save_be_uint32(tmp+4, dst.r); + + for(i=0;i<size;i++){ + p[i] = (uint8_t)(p[i] ^ tmp[i]); + } + } + + return 0; +} + +static int decrypt_multi2(void *m2, int32_t type, uint8_t *buf, int32_t size) +{ + CORE_DATA src,dst,cbc; + CORE_PARAM *prm; + + uint8_t *p; + + MULTI2_PRIVATE_DATA *prv; + + prv = private_data(m2); + if( (prv == NULL) || (buf == NULL) || (size < 1) ){ + return MULTI2_ERROR_INVALID_PARAMETER; + } + + if(prv->state != (MULTI2_STATE_CBC_INIT_SET|MULTI2_STATE_SYSTEM_KEY_SET|MULTI2_STATE_SCRAMBLE_KEY_SET)){ + if( (prv->state & MULTI2_STATE_CBC_INIT_SET) == 0 ){ + return MULTI2_ERROR_UNSET_CBC_INIT; + } + if( (prv->state & MULTI2_STATE_SYSTEM_KEY_SET) == 0 ){ + return MULTI2_ERROR_UNSET_SYSTEM_KEY; + } + if( (prv->state & MULTI2_STATE_SCRAMBLE_KEY_SET) == 0 ){ + return MULTI2_ERROR_UNSET_SCRAMBLE_KEY; + } + } + + if(type == 0x02){ + prm = prv->wrk+1; + }else{ + prm = prv->wrk+0; + } + + cbc.l = prv->cbc_init.l; + cbc.r = prv->cbc_init.r; + + p = buf; + while(size >= 8){ + load_be_uint32(&(src.l), p+0); + load_be_uint32(&(src.r), p+4); + core_decrypt(&dst, &src, prm, prv->round); + dst.l = dst.l ^ cbc.l; + dst.r = dst.r ^ cbc.r; + cbc.l = src.l; + cbc.r = src.r; + p = save_be_uint32(p, dst.l); + p = save_be_uint32(p, dst.r); + size -= 8; + } + + if(size > 0){ + int i; + uint8_t tmp[8]; + + core_encrypt(&dst, &cbc, prm, prv->round); + save_be_uint32(tmp+0, dst.l); + save_be_uint32(tmp+4, dst.r); + + for(i=0;i<size;i++){ + p[i] = (uint8_t)(p[i] ^ tmp[i]); + } + } + + return 0; +} + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + private method implementation + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +static MULTI2_PRIVATE_DATA *private_data(void *m2) +{ + MULTI2_PRIVATE_DATA *r; + MULTI2 *p; + + p = (MULTI2 *)m2; + if(p == NULL){ + return NULL; + } + + r = (MULTI2_PRIVATE_DATA *)(p->private_data); + if( ((void *)(r+1)) != ((void *)p) ){ + return NULL; + } + + return r; +} + +static void core_schedule(CORE_PARAM *work, CORE_PARAM *skey, CORE_DATA *dkey) +{ + CORE_DATA b1,b2,b3,b4,b5,b6,b7,b8,b9; + + core_pi1(&b1, dkey); + + core_pi2(&b2, &b1, skey->key[0]); + work->key[0] = b2.l; + + core_pi3(&b3, &b2, skey->key[1], skey->key[2]); + work->key[1] = b3.r; + + core_pi4(&b4, &b3, skey->key[3]); + work->key[2] = b4.l; + + core_pi1(&b5, &b4); + work->key[3] = b5.r; + + core_pi2(&b6, &b5, skey->key[4]); + work->key[4] = b6.l; + + core_pi3(&b7, &b6, skey->key[5], skey->key[6]); + work->key[5] = b7.r; + + core_pi4(&b8, &b7, skey->key[7]); + work->key[6] = b8.l; + + core_pi1(&b9, &b8); + work->key[7] = b9.r; +} + +static void core_encrypt(CORE_DATA *dst, CORE_DATA *src, CORE_PARAM *w, int32_t round) +{ + int32_t i; + + CORE_DATA tmp; + + dst->l = src->l; + dst->r = src->r; + for(i=0;i<round;i++){ + core_pi1(&tmp, dst); + core_pi2( dst, &tmp, w->key[0]); + core_pi3(&tmp, dst, w->key[1], w->key[2]); + core_pi4( dst, &tmp, w->key[3]); + core_pi1(&tmp, dst); + core_pi2( dst, &tmp, w->key[4]); + core_pi3(&tmp, dst, w->key[5], w->key[6]); + core_pi4( dst, &tmp, w->key[7]); + } +} + +static void core_decrypt(CORE_DATA *dst, CORE_DATA *src, CORE_PARAM *w, int32_t round) +{ + int32_t i; + + CORE_DATA tmp; + + dst->l = src->l; + dst->r = src->r; + for(i=0;i<round;i++){ + core_pi4(&tmp, dst, w->key[7]); + core_pi3( dst, &tmp, w->key[5], w->key[6]); + core_pi2(&tmp, dst, w->key[4]); + core_pi1( dst, &tmp); + core_pi4(&tmp, dst, w->key[3]); + core_pi3( dst, &tmp, w->key[1], w->key[2]); + core_pi2(&tmp, dst, w->key[0]); + core_pi1( dst, &tmp); + } +} + +static void core_pi1(CORE_DATA *dst, CORE_DATA *src) +{ + dst->l = src->l; + dst->r = src->r ^ src->l; +} + +static void core_pi2(CORE_DATA *dst, CORE_DATA *src, uint32_t a) +{ + uint32_t t0,t1,t2; + + t0 = src->r + a; + t1 = left_rotate_uint32(t0, 1) + t0 - 1; + t2 = left_rotate_uint32(t1, 4) ^ t1; + + dst->l = src->l ^ t2; + dst->r = src->r; +} + +static void core_pi3(CORE_DATA *dst, CORE_DATA *src, uint32_t a, uint32_t b) +{ + uint32_t t0,t1,t2,t3,t4,t5; + + t0 = src->l + a; + t1 = left_rotate_uint32(t0, 2) + t0 + 1; + t2 = left_rotate_uint32(t1, 8) ^ t1; + t3 = t2 + b; + t4 = left_rotate_uint32(t3, 1) - t3; + t5 = left_rotate_uint32(t4, 16) ^ (t4 | src->l); + + dst->l = src->l; + dst->r = src->r ^ t5; +} + +static void core_pi4(CORE_DATA *dst, CORE_DATA *src, uint32_t a) +{ + uint32_t t0,t1; + + t0 = src->r + a; + t1 = left_rotate_uint32(t0, 2) + t0 + 1; + + dst->l = src->l ^ t1; + dst->r = src->r; +}