/* Diversifies key using random UserKey Material * Implements RFC 4357 p 6.5 key diversification algorithm * * inputKey - 32byte key to be diversified * ukm - 8byte user key material * outputKey - 32byte buffer to store diversified key * */ void keyDiversifyCryptoPro(gost_ctx *ctx,const unsigned char *inputKey, const unsigned char *ukm, unsigned char *outputKey) { u4 k,s1,s2; int i,j,mask; unsigned char S[8]; memcpy(outputKey,inputKey,32); for (i=0;i<8;i++) { /* Make array of integers from key */ /* Compute IV S*/ s1=0,s2=0; for (j=0,mask=1;j<8;j++,mask<<=1) { k=((u4)outputKey[4*j])|(outputKey[4*j+1]<<8)| (outputKey[4*j+2]<<16)|(outputKey[4*j+3]<<24); if (mask & ukm[i]) { s1+=k; } else { s2+=k; } } S[0]=(unsigned char)(s1&0xff); S[1]=(unsigned char)((s1>>8)&0xff); S[2]=(unsigned char)((s1>>16)&0xff); S[3]=(unsigned char)((s1>>24)&0xff); S[4]=(unsigned char)(s2&0xff); S[5]=(unsigned char)((s2>>8)&0xff); S[6]=(unsigned char)((s2>>16)&0xff); S[7]=(unsigned char)((s2>>24)&0xff); gost_key(ctx,outputKey); gost_enc_cfb(ctx,S,outputKey,outputKey,4); } }
static int dstu_cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t inl) { size_t to_use, i, blocks; gost_ctx *gctx = ctx->cipher_data; unsigned char tmpiv[DSTU_CIPHER_BLOCK_SIZE], *out_start = out; if ((!inl) && (!in)) return 0; if ((!inl) || (!in)) return -1; if (ctx->num) { to_use = ((size_t)(ctx->num) < inl) ? (size_t)(ctx->num) : inl; for (i = 0; i < to_use; i++) { if (ctx->encrypt) { *out = *in ^ ctx->buf[DSTU_CIPHER_BLOCK_SIZE - ctx->num + i]; ctx->iv[DSTU_CIPHER_BLOCK_SIZE - ctx->num + i] = *out; } else { ctx->iv[DSTU_CIPHER_BLOCK_SIZE - ctx->num + i] = *in; *out = *in ^ ctx->buf[DSTU_CIPHER_BLOCK_SIZE - ctx->num + i]; } in++; out++; } ctx->num -= to_use; inl -= to_use; if (!ctx->num) gostcrypt(gctx, ctx->iv, ctx->buf); } if (inl) { blocks = inl >> 3; if (blocks) { if (ctx->encrypt) { gost_enc_cfb(gctx, ctx->iv, in, out, blocks); memcpy(ctx->iv, out + (blocks * DSTU_CIPHER_BLOCK_SIZE) - DSTU_CIPHER_BLOCK_SIZE, DSTU_CIPHER_BLOCK_SIZE); } else { memcpy(tmpiv, ctx->iv, DSTU_CIPHER_BLOCK_SIZE); memcpy(ctx->iv, in + (blocks * DSTU_CIPHER_BLOCK_SIZE) - DSTU_CIPHER_BLOCK_SIZE, DSTU_CIPHER_BLOCK_SIZE); gost_dec_cfb(gctx, tmpiv, in, out, blocks); } gostcrypt(gctx, ctx->iv, ctx->buf); out += blocks * DSTU_CIPHER_BLOCK_SIZE; in += blocks * DSTU_CIPHER_BLOCK_SIZE; inl -= blocks * DSTU_CIPHER_BLOCK_SIZE; } } if (inl) { for (i = 0; i < inl; i++) { if (ctx->encrypt) { *out = *in ^ ctx->buf[i]; ctx->iv[i] = *out; } else { ctx->iv[i] = *in; *out = *in ^ ctx->buf[i]; } in++; out++; } ctx->num = DSTU_CIPHER_BLOCK_SIZE - inl; } return out - out_start; }