diff --git a/include/ica_api.h b/include/ica_api.h index a1ac3dda..00a922c5 100644 --- a/include/ica_api.h +++ b/include/ica_api.h @@ -125,6 +125,8 @@ typedef ica_adapter_handle_t ICA_ADAPTER_HANDLE; #define RSA_KEY_GEN_ME 92 #define RSA_KEY_GEN_CRT 93 #define SHA512_DRNG 94 +#define SHA512_224 95 +#define SHA512_256 96 /* * Key length for DES/3DES encryption/decryption @@ -156,6 +158,8 @@ typedef ica_adapter_handle_t ICA_ADAPTER_HANDLE; #define SHA256_HASH_LENGTH 32 #define SHA384_HASH_LENGTH 48 #define SHA512_HASH_LENGTH 64 +#define SHA512_224_HASH_LENGTH SHA224_HASH_LENGTH +#define SHA512_256_HASH_LENGTH SHA256_HASH_LENGTH #define SHA3_224_HASH_LENGTH SHA224_HASH_LENGTH #define SHA3_256_HASH_LENGTH SHA256_HASH_LENGTH #define SHA3_384_HASH_LENGTH SHA384_HASH_LENGTH @@ -715,6 +719,93 @@ unsigned int ica_sha512(unsigned int message_part, sha512_context_t *sha512_context, unsigned char *output_data); +/** + * Perform secure hash on input data using the SHA-512/224 algorithm. + * + * Required HW Support + * KIMD-SHA-512, or KLMD-SHA-512 + * + * @param message_part + * The message chaining state. Must be one of the following: + * SHA_MSG_PART_ONLY - A single hash operation + * SHA_MSG_PART_FIRST - The first part + * SHA_MSG_PART_MIDDLE - The middle part + * SHA_MSG_PART_FINAL - The last part + * @param input_length + * The byte length of the input data to be SHA-512/224 hashed and must be greater + * than zero. + * Note: For SHA_MSG_PART_FIRST and SHA_MSG_PART_MIDDLE calls, the byte length + * must be a multiple of 128 i.e., SHA-512 block size. + * @param input_data + * Pointer to the input data. + * @param sha512_context + * Pointer to the SHA-512 context structure used to store intermediate values + * needed when chaining is used. The contents are ignored for message part + * SHA_MSG_PART_ONLY and SHA_MSG_PART_FIRST. This structure must + * contain the returned value of the preceding call to ica_sha512_224 for message + * part SHA_MSG_PART_MIDDLE and SHA_MSG_PART_FINAL. For message part + * SHA_MSG_PART_FIRST and SHA_MSG_PART_FINAL, the returned value can + * be used for a chained call of ica_sha512_224. Therefore, the application must + * not modify the contents of this structure in between chained calls. + * @param output_data + * Pointer to the buffer to contain the resulting hash data. The resulting + * output data will have a length of SHA512_224_HASH_LENGTH. Make sure buffer has + * at least this size. + * + * @return 0 if successful. + * EINVAL if at least one invalid parameter is given + * EIO if the operation fails. This should never happen. + */ +ICA_EXPORT +unsigned int ica_sha512_224(unsigned int message_part, + uint64_t input_length, + unsigned char *input_data, + sha512_context_t *sha512_context, + unsigned char *output_data); + +/** + * Perform secure hash on input data using the SHA-512/256 algorithm. + * + * Required HW Support + * KIMD-SHA-512, or KLMD-SHA-512 + * + * @param message_part + * The message chaining state. Must be one of the following: + * SHA_MSG_PART_ONLY - A single hash operation + * SHA_MSG_PART_FIRST - The first part + * SHA_MSG_PART_MIDDLE - The middle part + * SHA_MSG_PART_FINAL - The last part + * @param input_length + * The byte length of the input data to be SHA-512/256 hashed and must be greater + * than zero. + * Note: For SHA_MSG_PART_FIRST and SHA_MSG_PART_MIDDLE calls, the byte length + * must be a multiple of 128 i.e., SHA-512 block size. + * @param input_data + * Pointer to the input data. + * @param sha512_context + * Pointer to the SHA-512 context structure used to store intermediate values + * needed when chaining is used. The contents are ignored for message part + * SHA_MSG_PART_ONLY and SHA_MSG_PART_FIRST. This structure must + * contain the returned value of the preceding call to ica_sha512_256 for message + * part SHA_MSG_PART_MIDDLE and SHA_MSG_PART_FINAL. For message part + * SHA_MSG_PART_FIRST and SHA_MSG_PART_FINAL, the returned value can + * be used for a chained call of ica_sha512_256. Therefore, the application must + * not modify the contents of this structure in between chained calls. + * @param output_data + * Pointer to the buffer to contain the resulting hash data. The resulting + * output data will have a length of SHA512_256_HASH_LENGTH. Make sure buffer has + * at least this size. + * + * @return 0 if successful. + * EINVAL if at least one invalid parameter is given + * EIO if the operation fails. This should never happen. + */ICA_EXPORT +unsigned int ica_sha512_256(unsigned int message_part, + uint64_t input_length, + unsigned char *input_data, + sha512_context_t *sha512_context, + unsigned char *output_data); + ICA_EXPORT unsigned int ica_sha3_224(unsigned int message_part, unsigned int input_length, diff --git a/libica.map b/libica.map index d8d6509c..f75f098e 100644 --- a/libica.map +++ b/libica.map @@ -126,3 +126,10 @@ LIBICA_3.3.0 { ica_mp_sqr512; local: *; } LIBICA_3.2.0; + +LIBICA_3.4.0 { + global: + ica_sha512_224; + ica_sha512_256; + local: *; +} LIBICA_3.3.0; diff --git a/src/ica_api.c b/src/ica_api.c index 3de21fcf..fef5463b 100644 --- a/src/ica_api.c +++ b/src/ica_api.c @@ -561,6 +561,84 @@ unsigned int ica_sha512(unsigned int message_part, (uint64_t *) &sha512_context->runningLengthHigh); } +unsigned int ica_sha512_224(unsigned int message_part, + uint64_t input_length, + unsigned char *input_data, + sha512_context_t *sha512_context, + unsigned char *output_data) +{ + unsigned int rc; + +#ifdef ICA_FIPS + if (fips >> 1) + return EACCES; +#endif /* ICA_FIPS */ + + /* check for obvious errors in parms */ + if ((input_data == NULL) || + (sha512_context == NULL) || + (output_data == NULL)) + return EINVAL; + + /* make sure some message part is specified */ + rc = check_message_part(message_part); + if (rc) + return rc; + + /* + * for FIRST or MIDDLE calls the input + * data length must be a multiple of 128 bytes. + */ + if (input_length & 0x7f && + (message_part == SHA_MSG_PART_FIRST || + message_part == SHA_MSG_PART_MIDDLE)) + return EINVAL; + + return s390_sha512_224((unsigned char *)&sha512_context->sha512Hash, + input_data, input_length, output_data, message_part, + (uint64_t *) &sha512_context->runningLengthLow, + (uint64_t *) &sha512_context->runningLengthHigh); +} + +unsigned int ica_sha512_256(unsigned int message_part, + uint64_t input_length, + unsigned char *input_data, + sha512_context_t *sha512_context, + unsigned char *output_data) +{ + unsigned int rc; + +#ifdef ICA_FIPS + if (fips >> 1) + return EACCES; +#endif /* ICA_FIPS */ + + /* check for obvious errors in parms */ + if ((input_data == NULL) || + (sha512_context == NULL) || + (output_data == NULL)) + return EINVAL; + + /* make sure some message part is specified */ + rc = check_message_part(message_part); + if (rc) + return rc; + + /* + * for FIRST or MIDDLE calls the input + * data length must be a multiple of 128 bytes. + */ + if (input_length & 0x7f && + (message_part == SHA_MSG_PART_FIRST || + message_part == SHA_MSG_PART_MIDDLE)) + return EINVAL; + + return s390_sha512_256((unsigned char *)&sha512_context->sha512Hash, + input_data, input_length, output_data, message_part, + (uint64_t *) &sha512_context->runningLengthLow, + (uint64_t *) &sha512_context->runningLengthHigh); +} + unsigned int ica_sha3_224(unsigned int message_part, unsigned int input_length, unsigned char *input_data, diff --git a/src/icainfo.c b/src/icainfo.c index 410208af..e2a79f31 100644 --- a/src/icainfo.c +++ b/src/icainfo.c @@ -76,6 +76,8 @@ static struct crypt_pair crypt_map[] = { {"SHA-256", SHA256}, {"SHA-384", SHA384}, {"SHA-512", SHA512}, + {"SHA-512/224", SHA512_224}, + {"SHA-512/256", SHA512_256}, {"SHA3-224", SHA3_224}, {"SHA3-256", SHA3_256}, {"SHA3-384", SHA3_384}, diff --git a/src/include/icastats.h b/src/include/icastats.h index 3dbe0858..f5e97a8e 100644 --- a/src/include/icastats.h +++ b/src/include/icastats.h @@ -35,6 +35,8 @@ typedef enum stats_fields { ICA_STATS_SHA256, ICA_STATS_SHA384, ICA_STATS_SHA512, + ICA_STATS_SHA512_224, + ICA_STATS_SHA512_256, ICA_STATS_SHA3_224, ICA_STATS_SHA3_256, ICA_STATS_SHA3_384, @@ -84,6 +86,8 @@ typedef enum stats_fields { "SHA-256", \ "SHA-384", \ "SHA-512", \ + "SHA-512/224", \ + "SHA-512/256", \ "SHA3-224", \ "SHA3-256", \ "SHA3-384", \ diff --git a/src/include/s390_crypto.h b/src/include/s390_crypto.h index d8f7ce96..154242d2 100644 --- a/src/include/s390_crypto.h +++ b/src/include/s390_crypto.h @@ -125,7 +125,9 @@ typedef enum { SHA_3_512, SHAKE_128, SHAKE_256, - GHASH + GHASH, + SHA_512_224, + SHA_512_256 } kimd_functions_t; typedef enum { diff --git a/src/include/s390_sha.h b/src/include/s390_sha.h index 6a725ec2..b8070672 100644 --- a/src/include/s390_sha.h +++ b/src/include/s390_sha.h @@ -44,6 +44,22 @@ static unsigned char SHA_512_DEFAULT_IV[] = { 0x1f, 0x83, 0xd9, 0xab, 0xfb, 0x41, 0xbd, 0x6b, 0x5b, 0xe0, 0xcd, 0x19, 0x13, 0x7e, 0x21, 0x79 }; +static unsigned char SHA_512_224_DEFAULT_IV[] = { + 0x8C, 0x3D, 0x37, 0xC8, 0x19, 0x54, 0x4D, 0xA2, 0x73, 0xE1, 0x99, 0x66, + 0x89, 0xDC, 0xD4, 0xD6, 0x1D, 0xFA, 0xB7, 0xAE, 0x32, 0xFF, 0x9C, 0x82, + 0x67, 0x9D, 0xD5, 0x14, 0x58, 0x2F, 0x9F, 0xCF, 0x0F, 0x6D, 0x2B, 0x69, + 0x7B, 0xD4, 0x4D, 0xA8, 0x77, 0xE3, 0x6F, 0x73, 0x04, 0xC4, 0x89, 0x42, + 0x3F, 0x9D, 0x85, 0xA8, 0x6A, 0x1D, 0x36, 0xC8, 0x11, 0x12, 0xE6, 0xAD, + 0x91, 0xD6, 0x92, 0xA1 }; + +static unsigned char SHA_512_256_DEFAULT_IV[] = { + 0x22, 0x31, 0x21, 0x94, 0xFC, 0x2B, 0xF7, 0x2C, 0x9F, 0x55, 0x5F, 0xA3, + 0xC8, 0x4C, 0x64, 0xC2, 0x23, 0x93, 0xB8, 0x6B, 0x6F, 0x53, 0xB1, 0x51, + 0x96, 0x38, 0x77, 0x19, 0x59, 0x40, 0xEA, 0xBD, 0x96, 0x28, 0x3E, 0xE2, + 0xA8, 0x8E, 0xFF, 0xE3, 0xBE, 0x5E, 0x1E, 0x25, 0x53, 0x86, 0x39, 0x92, + 0x2B, 0x01, 0x99, 0xFC, 0x2C, 0x85, 0xB8, 0xAA, 0x0E, 0xB7, 0x2D, 0xDC, + 0x81, 0xC5, 0x2C, 0xA2 }; + static unsigned char SHA_3_DEFAULT_IV[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -82,7 +98,10 @@ static const SHA_CONSTANTS sha_constants[] = { {S390_CRYPTO_SHA_3_384, 48, 200, 104, SHA_3_DEFAULT_IV}, {S390_CRYPTO_SHA_3_512, 64, 200, 72, SHA_3_DEFAULT_IV}, {S390_CRYPTO_SHAKE_128, 0, 200, 168, SHA_3_DEFAULT_IV}, - {S390_CRYPTO_SHAKE_256, 0, 200, 136, SHA_3_DEFAULT_IV} + {S390_CRYPTO_SHAKE_256, 0, 200, 136, SHA_3_DEFAULT_IV}, + { 0, 0, 0, 0, NULL }, /* Dummy line for GHASH */ + {S390_CRYPTO_SHA_512, 28, 64, 128, SHA_512_224_DEFAULT_IV}, + {S390_CRYPTO_SHA_512, 32, 64, 128, SHA_512_256_DEFAULT_IV}, }; int s390_sha1(unsigned char *iv, unsigned char *input_data, @@ -107,6 +126,16 @@ int s390_sha512(unsigned char *iv, unsigned char *input_data, unsigned int message_part, uint64_t *running_length_lo, uint64_t *running_length_hi); +int s390_sha512_224(unsigned char *iv, unsigned char *input_data, + uint64_t input_length, unsigned char *output_data, + unsigned int message_part, uint64_t *running_length_lo, + uint64_t *running_length_hi); + +int s390_sha512_256(unsigned char *iv, unsigned char *input_data, + uint64_t input_length, unsigned char *output_data, + unsigned int message_part, uint64_t *running_length_lo, + uint64_t *running_length_hi); + int s390_sha3_224(unsigned char *iv, unsigned char *input_data, unsigned int input_length, unsigned char *output_data, unsigned int message_part, uint64_t *running_length); diff --git a/src/s390_crypto.c b/src/s390_crypto.c index 1aa0f4c1..7a262cb1 100644 --- a/src/s390_crypto.c +++ b/src/s390_crypto.c @@ -47,7 +47,9 @@ s390_supported_function_t s390_kimd_functions[] = { {SHA_3_512, S390_CRYPTO_SHA_3_512, &sha3_switch}, {SHAKE_128, S390_CRYPTO_SHAKE_128, &sha3_switch}, {SHAKE_256, S390_CRYPTO_SHAKE_256, &sha3_switch}, - {GHASH, S390_CRYPTO_GHASH, &msa4_switch} + {GHASH, S390_CRYPTO_GHASH, &msa4_switch}, + {SHA_512_224, S390_CRYPTO_SHA_512, &sha512_switch}, + {SHA_512_256, S390_CRYPTO_SHA_512, &sha512_switch} }; s390_supported_function_t s390_kmc_functions[] = { @@ -298,6 +300,8 @@ libica_func_list_element_int icaList[] = { {SHA256, KIMD, SHA_256, ICA_FLAG_SW, 0}, {SHA384, KIMD, SHA_512, ICA_FLAG_SW, 0}, {SHA512, KIMD, SHA_512, ICA_FLAG_SW, 0}, + {SHA512_224, KIMD, SHA_512_224, ICA_FLAG_SW, 0}, + {SHA512_256, KIMD, SHA_512_256, ICA_FLAG_SW, 0}, {SHA3_224, KIMD, SHA_3_224, 0, 0}, {SHA3_256, KIMD, SHA_3_256, 0, 0}, {SHA3_384, KIMD, SHA_3_384, 0, 0}, diff --git a/src/s390_sha.c b/src/s390_sha.c index 74346206..402d206e 100644 --- a/src/s390_sha.c +++ b/src/s390_sha.c @@ -225,6 +225,102 @@ int s390_sha512_sw(unsigned char *iv, unsigned char *input_data, return 0; } +int s390_sha512_224_sw(unsigned char *iv, unsigned char *input_data, + uint64_t input_length, unsigned char *output_data, + unsigned int message_part, uint64_t *running_length_lo, + uint64_t *running_length_hi) +{ + SHA512_CTX ctx; + unsigned int vector_length = 64; + +#ifdef ICA_FIPS + if ((fips & ICA_FIPS_MODE) && (!FIPS_mode())) + return EACCES; +#endif /* ICA_FIPS */ + + if (message_part == SHA_MSG_PART_ONLY || message_part == SHA_MSG_PART_FIRST) { + SHA512_Init(&ctx); + /* SHA-512/224 uses a distinct initial hash value */ + ctx.h[0] = U64(0x8c3d37c819544da2); + ctx.h[1] = U64(0x73e1996689dcd4d6); + ctx.h[2] = U64(0x1dfab7ae32ff9c82); + ctx.h[3] = U64(0x679dd514582f9fcf); + ctx.h[4] = U64(0x0f6d2b697bd44da8); + ctx.h[5] = U64(0x77e36f7304c48942); + ctx.h[6] = U64(0x3f9d85a86a1d36c8); + ctx.h[7] = U64(0x1112e6ad91d692a1); + } else { + ctx.md_len = SHA224_DIGEST_LENGTH; + ctx.Nl = *running_length_lo; + ctx.Nh = *running_length_hi; + ctx.num = 0; + memcpy((unsigned char *) &ctx.h[0], iv, vector_length); + } + + SHA512_Update(&ctx, input_data, input_length); + + if (message_part == SHA_MSG_PART_ONLY || + message_part == SHA_MSG_PART_FINAL) + SHA512_Final(output_data, &ctx); + else { + *running_length_lo = ctx.Nl; + *running_length_hi = ctx.Nh; + memcpy(output_data, (unsigned char *) &ctx.h[0], + SHA224_DIGEST_LENGTH); + memcpy(iv, (unsigned char *) &ctx.h[0], vector_length); + } + + return 0; +} + +int s390_sha512_256_sw(unsigned char *iv, unsigned char *input_data, + uint64_t input_length, unsigned char *output_data, + unsigned int message_part, uint64_t *running_length_lo, + uint64_t *running_length_hi) +{ + SHA512_CTX ctx; + unsigned int vector_length = 64; + +#ifdef ICA_FIPS + if ((fips & ICA_FIPS_MODE) && (!FIPS_mode())) + return EACCES; +#endif /* ICA_FIPS */ + + if (message_part == SHA_MSG_PART_ONLY || message_part == SHA_MSG_PART_FIRST) { + SHA512_Init(&ctx); + /* SHA-512/256 uses a distinct initial hash value */ + ctx.h[0] = U64(0x22312194fc2bf72c); + ctx.h[1] = U64(0x9f555fa3c84c64c2); + ctx.h[2] = U64(0x2393b86b6f53b151); + ctx.h[3] = U64(0x963877195940eabd); + ctx.h[4] = U64(0x96283ee2a88effe3); + ctx.h[5] = U64(0xbe5e1e2553863992); + ctx.h[6] = U64(0x2b0199fc2c85b8aa); + ctx.h[7] = U64(0x0eb72ddc81c52ca2); + } else { + ctx.md_len = SHA256_DIGEST_LENGTH; + ctx.Nl = *running_length_lo; + ctx.Nh = *running_length_hi; + ctx.num = 0; + memcpy((unsigned char *) &ctx.h[0], iv, vector_length); + } + + SHA512_Update(&ctx, input_data, input_length); + + if (message_part == SHA_MSG_PART_ONLY || + message_part == SHA_MSG_PART_FINAL) + SHA512_Final(output_data, &ctx); + else { + *running_length_lo = ctx.Nl; + *running_length_hi = ctx.Nh; + memcpy(output_data, (unsigned char *) &ctx.h[0], + SHA256_DIGEST_LENGTH); + memcpy(iv, (unsigned char *) &ctx.h[0], vector_length); + } + + return 0; +} + int s390_sha1(unsigned char *iv, unsigned char *input_data, unsigned int input_length, unsigned char *output_data, unsigned int message_part, uint64_t *running_length) @@ -335,6 +431,54 @@ int s390_sha512(unsigned char *iv, unsigned char *input_data, return rc; } +int s390_sha512_224(unsigned char *iv, unsigned char *input_data, + uint64_t input_length, unsigned char *output_data, + unsigned int message_part, uint64_t *running_length_lo, + uint64_t *running_length_hi) +{ + int rc = ENODEV; + if (sha512_switch) + rc = s390_sha_hw(iv, input_data, input_length, output_data, + sha_constants[SHA_512_224].hash_length, + message_part, running_length_lo, + running_length_hi, SHA_512_224); + if (rc) { + if (!ica_fallbacks_enabled) + return rc; + rc = s390_sha512_224_sw(iv, input_data, input_length, output_data, + message_part, running_length_lo, + running_length_hi); + stats_increment(ICA_STATS_SHA512_224, ALGO_SW, ENCRYPT); + } else + stats_increment(ICA_STATS_SHA512_224, ALGO_HW, ENCRYPT); + + return rc; +} + +int s390_sha512_256(unsigned char *iv, unsigned char *input_data, + uint64_t input_length, unsigned char *output_data, + unsigned int message_part, uint64_t *running_length_lo, + uint64_t *running_length_hi) +{ + int rc = ENODEV; + if (sha512_switch) + rc = s390_sha_hw(iv, input_data, input_length, output_data, + sha_constants[SHA_512_256].hash_length, + message_part, running_length_lo, + running_length_hi, SHA_512_256); + if (rc) { + if (!ica_fallbacks_enabled) + return rc; + rc = s390_sha512_256_sw(iv, input_data, input_length, output_data, + message_part, running_length_lo, + running_length_hi); + stats_increment(ICA_STATS_SHA512_256, ALGO_SW, ENCRYPT); + } else + stats_increment(ICA_STATS_SHA512_256, ALGO_HW, ENCRYPT); + + return rc; +} + int s390_sha3_224(unsigned char *iv, unsigned char *input_data, unsigned int input_length, unsigned char *output_data, unsigned int message_part, uint64_t *running_length)