int FIPS_selftest_des() { int n; /* Encrypt/decrypt with DES and compare to known answers */ for(n=0 ; n < 2 ; ++n) { DES_key_schedule key; DES_cblock buf; DES_set_key(&tests[n].key,&key); DES_ecb_encrypt(&tests[n].plaintext,&buf,&key,1); if(memcmp(buf,tests[n].ciphertext,sizeof buf)) { FIPSerr(FIPS_F_FIPS_SELFTEST_DES,FIPS_R_SELFTEST_FAILED); return 0; } DES_ecb_encrypt(&tests[n].ciphertext,&buf,&key,0); if(memcmp(buf,tests[n].plaintext,sizeof buf)) { FIPSerr(FIPS_F_FIPS_SELFTEST_DES,FIPS_R_SELFTEST_FAILED); return 0; } } /* Encrypt/decrypt with 2-key 3DES and compare to known answers */ for(n=0 ; n < 2 ; ++n) { DES_key_schedule key1, key2; unsigned char buf[8]; DES_set_key(&tests2[n].key1,&key1); DES_set_key(&tests2[n].key2,&key2); DES_ecb2_encrypt(tests2[n].plaintext,buf,&key1,&key2,1); if(memcmp(buf,tests2[n].ciphertext,sizeof buf)) { FIPSerr(FIPS_F_FIPS_SELFTEST_DES,FIPS_R_SELFTEST_FAILED); return 0; } DES_ecb2_encrypt(tests2[n].ciphertext,buf,&key1,&key2,0); if(memcmp(buf,tests2[n].plaintext,sizeof buf)) { FIPSerr(FIPS_F_FIPS_SELFTEST_DES,FIPS_R_SELFTEST_FAILED); return 0; } } /* Encrypt/decrypt with 3DES and compare to known answers */ for(n=0 ; n < 2 ; ++n) { DES_key_schedule key1, key2, key3; unsigned char buf[8]; DES_set_key(&tests3[n].key1,&key1); DES_set_key(&tests3[n].key2,&key2); DES_set_key(&tests3[n].key3,&key3); DES_ecb3_encrypt(tests3[n].plaintext,buf,&key1,&key2,&key3,1); if(memcmp(buf,tests3[n].ciphertext,sizeof buf)) { FIPSerr(FIPS_F_FIPS_SELFTEST_DES,FIPS_R_SELFTEST_FAILED); return 0; } DES_ecb3_encrypt(tests3[n].ciphertext,buf,&key1,&key2,&key3,0); if(memcmp(buf,tests3[n].plaintext,sizeof buf)) { FIPSerr(FIPS_F_FIPS_SELFTEST_DES,FIPS_R_SELFTEST_FAILED); return 0; } } return 1; }
static int cardos_sm4h(const unsigned char *in, size_t inlen, unsigned char *out, size_t outlen, const unsigned char *key, size_t keylen) { /* using a buffer with an APDU, build an SM 4h APDU for cardos */ int plain_lc; /* data size in orig APDU */ unsigned int mac_input_len, enc_input_len; unsigned char *mac_input, *enc_input; DES_key_schedule ks_a, ks_b; DES_cblock des_in,des_out; unsigned int i,j; if (keylen != 16) { printf("key has wrong size, need 16 bytes, got %zd. aborting.\n", keylen); return 0; } if (inlen < 4) return 0; /* failed, apdu too short */ if (inlen <= 5) plain_lc = 0; if (inlen > 5) plain_lc = in[4]; /* 4 + plain_lc plus 0..7 bytes of padding */ mac_input_len = 4 + plain_lc; while (mac_input_len % 8) mac_input_len++; mac_input = calloc(1,mac_input_len); if (!mac_input) { printf("out of memory, aborting\n"); return 0; } mac_input[0] = in[1]; /* ins */ mac_input[1] = in[2]; /* p1 */ mac_input[2] = in[3]; /* p2 */ mac_input[3] = plain_lc + 8; if (plain_lc) /* copy data from in APDU */ memcpy(&mac_input[4],&in[5],plain_lc); /* calloc already did the ansi padding: rest is 00 */ /* prepare des key using first 8 bytes of key */ DES_set_key((const_DES_cblock*) &key[0], &ks_a); /* prepare des key using second 8 bytes of key */ DES_set_key((const_DES_cblock*) &key[8], &ks_b); /* first block: XOR with IV and encrypt with key A IV is 8 bytes 00 */ for (i=0; i < 8; i++) des_in[i] = mac_input[i]^00; DES_ecb_encrypt(&des_in, &des_out, &ks_a, 1); /* all other blocks: XOR with prev. result and encrypt with key A */ for (j=1; j < (mac_input_len / 8); j++) { for (i=0; i < 8; i++) des_in[i] = mac_input[i+j*8]^des_out[i]; DES_ecb_encrypt(&des_in, &des_out, &ks_a, 1); } /* now decrypt with key B and encrypt with key A again */ /* (a noop if key A and B are the same, e.g. 8 bytes ff */ for (i=0; i < 8; i++) des_in[i] = des_out[i]; DES_ecb_encrypt(&des_in, &des_out, &ks_b, 0); for (i=0; i < 8; i++) des_in[i] = des_out[i]; DES_ecb_encrypt(&des_in, &des_out, &ks_a, 1); /* now we want to enc: * orig APDU data plus mac (8 bytes) plus iso padding (1-8 bytes) */ enc_input_len = plain_lc + 8 + 1; while (enc_input_len % 8) enc_input_len++; enc_input = calloc(1,enc_input_len); if (!enc_input) { free(mac_input); printf("out of memory, aborting\n"); return 0; } if (plain_lc) memcpy(&enc_input[0],&in[5],plain_lc); for (i=0; i < 8; i++) enc_input[i+plain_lc] = des_out[i]; enc_input[plain_lc+8] = 0x80; /* iso padding */ /* calloc already cleard the remaining bytes to 00 */ if (outlen < 5 + enc_input_len) { free(mac_input); free(enc_input); printf("output buffer too small, aborting.\n"); return 0; } out[0] = in[0]; /* cla */ out[1] = in[1]; /* ins */ out[2] = in[2]; /* p1 */ out[3] = in[3]; /* p2 */ out[4] = enc_input_len; /* lc */ /* encrypt first block */ /* xor data and IV (8 bytes 00) to get input data */ for (i=0; i < 8; i++) des_in[i] = enc_input[i] ^ 00; /* encrypt with des2 (tripple des, but using keys A-B-A) */ DES_ecb2_encrypt(&des_in, &des_out, &ks_a, &ks_b, 1); /* copy encrypted bytes into output */ for (i=0; i < 8; i++) out[5+i] = des_out[i]; /* encrypt other blocks (usualy one) */ for (j=1; j < (enc_input_len / 8); j++) { /* xor data and prev. result to get input data */ for (i=0; i < 8; i++) des_in[i] = enc_input[i+j*8] ^ des_out[i]; /* encrypt with des2 (tripple des, but using keys A-B-A) */ DES_ecb2_encrypt(&des_in, &des_out, &ks_a, &ks_b, 1); /* copy encrypted bytes into output */ for (i=0; i < 8; i++) out[5+8*j+i] = des_out[i]; } if (verbose) { printf ("Unencrypted APDU:\n"); util_hex_dump_asc(stdout, in, inlen, -1); printf ("Encrypted APDU:\n"); util_hex_dump_asc(stdout, out, out[4] + 5, -1); printf ("\n"); } free(mac_input); free(enc_input); return 1; }
static crypto_error_t crypto_cipher(bytestring_t *dst, const bytestring_t *ctx, const bytestring_t *src, const bytestring_t *iv, int enc) { unsigned u; unsigned char alg; DES_key_schedule key_schedule; DES_key_schedule key_schedule2; if (bytestring_get_element(&alg,ctx,0)!=BYTESTRING_OK) return CRYPTO_ERROR_UNKNOWN; if ((bytestring_get_size(src)&0x7)!=0) return CRYPTO_ERROR_BAD_CLEARTEXT_LENGTH; switch (alg) { case CRYPTO_ALG_DES_ECB: bytestring_resize(dst,bytestring_get_size(src)); memcpy(&key_schedule,ctx->data+KS_HEADER_SIZE,DES_KS_SIZE); for (u=0; u<bytestring_get_size(src)/8; u++) DES_ecb_encrypt((const_DES_cblock *)(src->data+u*8), (DES_cblock *)(dst->data+u*8), &key_schedule, enc); break; case CRYPTO_ALG_DES_CBC: if (iv==NULL || bytestring_get_size(iv)!=8) return CRYPTO_ERROR_BAD_IV_LENGTH; bytestring_resize(dst,bytestring_get_size(src)); memcpy(&key_schedule,ctx->data+KS_HEADER_SIZE,DES_KS_SIZE); DES_ncbc_encrypt(src->data, dst->data, bytestring_get_size(src), &key_schedule, (DES_cblock *)(iv->data), enc); break; case CRYPTO_ALG_DES2_EDE_ECB: bytestring_resize(dst,bytestring_get_size(src)); memcpy(&key_schedule,ctx->data+KS_HEADER_SIZE,DES_KS_SIZE); memcpy(&key_schedule2,ctx->data+KS_HEADER_SIZE+DES_KS_SIZE,DES_KS_SIZE); for (u=0; u<bytestring_get_size(src)/8; u++) DES_ecb2_encrypt((const_DES_cblock *)(src->data+u*8), (DES_cblock *)(dst->data+u*8), &key_schedule, &key_schedule2, enc); break; case CRYPTO_ALG_DES2_EDE_CBC: if (iv==NULL || bytestring_get_size(iv)!=8) return CRYPTO_ERROR_BAD_IV_LENGTH; bytestring_resize(dst,bytestring_get_size(src)); memcpy(&key_schedule,ctx->data+KS_HEADER_SIZE,DES_KS_SIZE); memcpy(&key_schedule2,ctx->data+KS_HEADER_SIZE+DES_KS_SIZE,DES_KS_SIZE); DES_ede2_cbc_encrypt(src->data, dst->data, bytestring_get_size(src), &key_schedule, &key_schedule2, (DES_cblock *)(iv->data), enc); break; default: return CRYPTO_ERROR_UNKNOWN_ALGORITHM; } return CRYPTO_OK; }