diff --git a/include/sys/crypto/common.h b/include/sys/crypto/common.h index 743805650057..a73804f916b6 100644 --- a/include/sys/crypto/common.h +++ b/include/sys/crypto/common.h @@ -1,170 +1,165 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or https://opensource.org/licenses/CDDL-1.0. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2013 Saso Kiselkov. All rights reserved. */ #ifndef _SYS_CRYPTO_COMMON_H #define _SYS_CRYPTO_COMMON_H /* * Header file for the common data structures of the cryptographic framework */ #ifdef __cplusplus extern "C" { #endif #include /* Cryptographic Mechanisms */ #define CRYPTO_MAX_MECH_NAME 32 typedef char crypto_mech_name_t[CRYPTO_MAX_MECH_NAME]; typedef uint64_t crypto_mech_type_t; typedef struct crypto_mechanism { crypto_mech_type_t cm_type; /* mechanism type */ caddr_t cm_param; /* mech. parameter */ size_t cm_param_len; /* mech. parameter len */ } crypto_mechanism_t; /* CK_AES_CCM_PARAMS provides parameters to the CKM_AES_CCM mechanism */ typedef struct CK_AES_CCM_PARAMS { ulong_t ulMACSize; ulong_t ulNonceSize; ulong_t ulAuthDataSize; ulong_t ulDataSize; /* used for plaintext or ciphertext */ uchar_t *nonce; uchar_t *authData; } CK_AES_CCM_PARAMS; /* CK_AES_GCM_PARAMS provides parameters to the CKM_AES_GCM mechanism */ typedef struct CK_AES_GCM_PARAMS { uchar_t *pIv; ulong_t ulIvLen; ulong_t ulIvBits; uchar_t *pAAD; ulong_t ulAADLen; ulong_t ulTagBits; } CK_AES_GCM_PARAMS; /* * The measurement unit bit flag for a mechanism's minimum or maximum key size. * The unit are mechanism dependent. It can be in bits or in bytes. */ typedef uint32_t crypto_keysize_unit_t; /* Mechanisms supported out-of-the-box */ -#define SUN_CKM_SHA256 "CKM_SHA256" #define SUN_CKM_SHA256_HMAC "CKM_SHA256_HMAC" #define SUN_CKM_SHA256_HMAC_GENERAL "CKM_SHA256_HMAC_GENERAL" -#define SUN_CKM_SHA384 "CKM_SHA384" #define SUN_CKM_SHA384_HMAC "CKM_SHA384_HMAC" #define SUN_CKM_SHA384_HMAC_GENERAL "CKM_SHA384_HMAC_GENERAL" -#define SUN_CKM_SHA512 "CKM_SHA512" #define SUN_CKM_SHA512_HMAC "CKM_SHA512_HMAC" #define SUN_CKM_SHA512_HMAC_GENERAL "CKM_SHA512_HMAC_GENERAL" -#define SUN_CKM_SHA512_224 "CKM_SHA512_224" -#define SUN_CKM_SHA512_256 "CKM_SHA512_256" #define SUN_CKM_AES_CCM "CKM_AES_CCM" #define SUN_CKM_AES_GCM "CKM_AES_GCM" /* Data arguments of cryptographic operations */ typedef enum crypto_data_format { CRYPTO_DATA_RAW = 1, CRYPTO_DATA_UIO, } crypto_data_format_t; typedef struct crypto_data { crypto_data_format_t cd_format; /* Format identifier */ off_t cd_offset; /* Offset from the beginning */ size_t cd_length; /* # of bytes in use */ union { /* Raw format */ iovec_t cd_raw; /* Pointer and length */ /* uio scatter-gather format */ zfs_uio_t *cd_uio; }; /* Crypto Data Union */ } crypto_data_t; /* The keys, and their contents */ typedef struct { uint_t ck_length; /* # of bits in ck_data */ void *ck_data; /* ptr to key value */ } crypto_key_t; /* * Raw key lengths are expressed in number of bits. * The following macro returns the minimum number of * bytes that can contain the specified number of bits. * Round up without overflowing the integer type. */ #define CRYPTO_BITS2BYTES(n) ((n) == 0 ? 0 : (((n) - 1) >> 3) + 1) #define CRYPTO_BYTES2BITS(n) ((n) << 3) /* Providers */ typedef uint32_t crypto_provider_id_t; #define KCF_PROVID_INVALID ((uint32_t)-1) /* session data structure opaque to the consumer */ typedef void *crypto_session_t; #define PROVIDER_OWNS_KEY_SCHEDULE 0x00000001 /* * Common cryptographic status and error codes. */ #define CRYPTO_SUCCESS 0x00000000 #define CRYPTO_HOST_MEMORY 0x00000002 #define CRYPTO_FAILED 0x00000004 #define CRYPTO_ARGUMENTS_BAD 0x00000005 #define CRYPTO_DATA_LEN_RANGE 0x0000000C #define CRYPTO_ENCRYPTED_DATA_LEN_RANGE 0x00000011 #define CRYPTO_KEY_SIZE_RANGE 0x00000013 #define CRYPTO_KEY_TYPE_INCONSISTENT 0x00000014 #define CRYPTO_MECHANISM_INVALID 0x0000001C #define CRYPTO_MECHANISM_PARAM_INVALID 0x0000001D #define CRYPTO_SIGNATURE_INVALID 0x0000002D #define CRYPTO_BUFFER_TOO_SMALL 0x00000042 #define CRYPTO_NOT_SUPPORTED 0x00000044 #define CRYPTO_INVALID_CONTEXT 0x00000047 #define CRYPTO_INVALID_MAC 0x00000048 #define CRYPTO_MECH_NOT_SUPPORTED 0x00000049 #define CRYPTO_INVALID_PROVIDER_ID 0x0000004C #define CRYPTO_BUSY 0x0000004E #define CRYPTO_UNKNOWN_PROVIDER 0x0000004F #ifdef __cplusplus } #endif #endif /* _SYS_CRYPTO_COMMON_H */ diff --git a/include/sys/sha2.h b/include/sys/sha2.h index 81dfbbb8cea9..2d38885bd966 100644 --- a/include/sys/sha2.h +++ b/include/sys/sha2.h @@ -1,127 +1,115 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or https://opensource.org/licenses/CDDL-1.0. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2022 Tino Reichardt */ #ifndef _SYS_SHA2_H #define _SYS_SHA2_H #ifdef _KERNEL #include #else #include #include #endif #ifdef __cplusplus extern "C" { #endif #define SHA224_BLOCK_LENGTH 64 #define SHA256_BLOCK_LENGTH 64 #define SHA384_BLOCK_LENGTH 128 #define SHA512_BLOCK_LENGTH 128 #define SHA224_DIGEST_LENGTH 28 #define SHA256_DIGEST_LENGTH 32 #define SHA384_DIGEST_LENGTH 48 #define SHA512_DIGEST_LENGTH 64 #define SHA512_224_DIGEST_LENGTH 28 #define SHA512_256_DIGEST_LENGTH 32 #define SHA256_HMAC_BLOCK_SIZE 64 #define SHA512_HMAC_BLOCK_SIZE 128 /* sha256 context */ typedef struct { uint32_t state[8]; uint64_t count[2]; uint8_t wbuf[64]; /* const sha256_ops_t *ops */ const void *ops; } sha256_ctx; /* sha512 context */ typedef struct { uint64_t state[8]; uint64_t count[2]; uint8_t wbuf[128]; /* const sha256_ops_t *ops */ const void *ops; } sha512_ctx; /* SHA2 context */ typedef struct { union { sha256_ctx sha256; sha512_ctx sha512; }; /* algorithm type */ int algotype; } SHA2_CTX; /* SHA2 algorithm types */ typedef enum sha2_mech_type { - SHA256_MECH_INFO_TYPE, /* SUN_CKM_SHA256 */ SHA256_HMAC_MECH_INFO_TYPE, /* SUN_CKM_SHA256_HMAC */ SHA256_HMAC_GEN_MECH_INFO_TYPE, /* SUN_CKM_SHA256_HMAC_GENERAL */ - SHA384_MECH_INFO_TYPE, /* SUN_CKM_SHA384 */ SHA384_HMAC_MECH_INFO_TYPE, /* SUN_CKM_SHA384_HMAC */ SHA384_HMAC_GEN_MECH_INFO_TYPE, /* SUN_CKM_SHA384_HMAC_GENERAL */ - SHA512_MECH_INFO_TYPE, /* SUN_CKM_SHA512 */ SHA512_HMAC_MECH_INFO_TYPE, /* SUN_CKM_SHA512_HMAC */ SHA512_HMAC_GEN_MECH_INFO_TYPE, /* SUN_CKM_SHA512_HMAC_GENERAL */ - SHA512_224_MECH_INFO_TYPE, /* SUN_CKM_SHA512_224 */ - SHA512_256_MECH_INFO_TYPE /* SUN_CKM_SHA512_256 */ -} sha2_mech_type_t; -#define SHA256 0 -#define SHA256_HMAC 1 -#define SHA256_HMAC_GEN 2 -#define SHA384 3 -#define SHA384_HMAC 4 -#define SHA384_HMAC_GEN 5 -#define SHA512 6 -#define SHA512_HMAC 7 -#define SHA512_HMAC_GEN 8 -#define SHA512_224 9 -#define SHA512_256 10 + /* Not true KCF mech types; used by direct callers to SHA2Init */ + SHA256, + SHA512, + SHA512_256, +} sha2_mech_type_t; /* SHA2 Init function */ extern void SHA2Init(int algotype, SHA2_CTX *ctx); /* SHA2 Update function */ extern void SHA2Update(SHA2_CTX *ctx, const void *data, size_t len); /* SHA2 Final function */ extern void SHA2Final(void *digest, SHA2_CTX *ctx); #ifdef __cplusplus } #endif #endif /* SYS_SHA2_H */ diff --git a/module/icp/algs/sha2/sha2_generic.c b/module/icp/algs/sha2/sha2_generic.c index 60d7ad9a1dfa..ab361b9d59f4 100644 --- a/module/icp/algs/sha2/sha2_generic.c +++ b/module/icp/algs/sha2/sha2_generic.c @@ -1,562 +1,540 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or https://opensource.org/licenses/CDDL-1.0. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Based on public domain code in cppcrypto 0.10. * Copyright (c) 2022 Tino Reichardt */ #include #include #include #include /* * On i386, gcc brings this for sha512_generic(): * error: the frame size of 1040 bytes is larger than 1024 */ #if defined(__GNUC__) && defined(_ILP32) #pragma GCC diagnostic ignored "-Wframe-larger-than=" #endif /* SHA256 */ static const uint32_t SHA256_K[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; #define Ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) #define Maj(x, y, z) (((y) & (z)) | (((y) | (z)) & (x))) #define rotr32(x, n) (((x) >> n) | ((x) << (32 - n))) #define sum0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22)) #define sum1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25)) #define sigma0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3)) #define sigma1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10)) #define WU(j) (W[j & 15] += sigma1(W[(j + 14) & 15]) \ + W[(j + 9) & 15] + sigma0(W[(j + 1) & 15])) #define COMPRESS(i, j, K) \ T1 = h + sum1(e) + Ch(e, f, g) + K[i + j] + (i? WU(j): W[j]); \ T2 = sum0(a) + Maj(a, b, c); \ h = g, g = f, f = e, e = d + T1; \ d = c, c = b, b = a, a = T1 + T2; static void sha256_generic(uint32_t state[8], const void *data, size_t num_blks) { uint64_t blk; for (blk = 0; blk < num_blks; blk++) { uint32_t W[16]; uint32_t a, b, c, d, e, f, g, h; uint32_t T1, T2; int i; for (i = 0; i < 16; i++) { W[i] = BE_32( \ (((const uint32_t *)(data))[blk * 16 + i])); } a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; for (i = 0; i <= 63; i += 16) { COMPRESS(i, 0, SHA256_K); COMPRESS(i, 1, SHA256_K); COMPRESS(i, 2, SHA256_K); COMPRESS(i, 3, SHA256_K); COMPRESS(i, 4, SHA256_K); COMPRESS(i, 5, SHA256_K); COMPRESS(i, 6, SHA256_K); COMPRESS(i, 7, SHA256_K); COMPRESS(i, 8, SHA256_K); COMPRESS(i, 9, SHA256_K); COMPRESS(i, 10, SHA256_K); COMPRESS(i, 11, SHA256_K); COMPRESS(i, 12, SHA256_K); COMPRESS(i, 13, SHA256_K); COMPRESS(i, 14, SHA256_K); COMPRESS(i, 15, SHA256_K); } state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; } } #undef sum0 #undef sum1 #undef sigma0 #undef sigma1 #define rotr64(x, n) (((x) >> n) | ((x) << (64 - n))) #define sum0(x) (rotr64((x), 28) ^ rotr64((x), 34) ^ rotr64((x), 39)) #define sum1(x) (rotr64((x), 14) ^ rotr64((x), 18) ^ rotr64((x), 41)) #define sigma0(x) (rotr64((x), 1) ^ rotr64((x), 8) ^ ((x) >> 7)) #define sigma1(x) (rotr64((x), 19) ^ rotr64((x), 61) ^ ((x) >> 6)) /* SHA512 */ static const uint64_t SHA512_K[80] = { 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 }; static void sha512_generic(uint64_t state[8], const void *data, size_t num_blks) { uint64_t blk; for (blk = 0; blk < num_blks; blk++) { uint64_t W[16]; uint64_t a, b, c, d, e, f, g, h; uint64_t T1, T2; int i; for (i = 0; i < 16; i++) { W[i] = BE_64( \ (((const uint64_t *)(data))[blk * 16 + i])); } a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; for (i = 0; i <= 79; i += 16) { COMPRESS(i, 0, SHA512_K); COMPRESS(i, 1, SHA512_K); COMPRESS(i, 2, SHA512_K); COMPRESS(i, 3, SHA512_K); COMPRESS(i, 4, SHA512_K); COMPRESS(i, 5, SHA512_K); COMPRESS(i, 6, SHA512_K); COMPRESS(i, 7, SHA512_K); COMPRESS(i, 8, SHA512_K); COMPRESS(i, 9, SHA512_K); COMPRESS(i, 10, SHA512_K); COMPRESS(i, 11, SHA512_K); COMPRESS(i, 12, SHA512_K); COMPRESS(i, 13, SHA512_K); COMPRESS(i, 14, SHA512_K); COMPRESS(i, 15, SHA512_K); } state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; } } static void sha256_update(sha256_ctx *ctx, const uint8_t *data, size_t len) { uint64_t pos = ctx->count[0]; uint64_t total = ctx->count[1]; uint8_t *m = ctx->wbuf; const sha256_ops_t *ops = ctx->ops; if (pos && pos + len >= 64) { memcpy(m + pos, data, 64 - pos); ops->transform(ctx->state, m, 1); len -= 64 - pos; total += (64 - pos) * 8; data += 64 - pos; pos = 0; } if (len >= 64) { uint32_t blocks = len / 64; uint32_t bytes = blocks * 64; ops->transform(ctx->state, data, blocks); len -= bytes; total += (bytes) * 8; data += bytes; } memcpy(m + pos, data, len); pos += len; total += len * 8; ctx->count[0] = pos; ctx->count[1] = total; } static void sha512_update(sha512_ctx *ctx, const uint8_t *data, size_t len) { uint64_t pos = ctx->count[0]; uint64_t total = ctx->count[1]; uint8_t *m = ctx->wbuf; const sha512_ops_t *ops = ctx->ops; if (pos && pos + len >= 128) { memcpy(m + pos, data, 128 - pos); ops->transform(ctx->state, m, 1); len -= 128 - pos; total += (128 - pos) * 8; data += 128 - pos; pos = 0; } if (len >= 128) { uint64_t blocks = len / 128; uint64_t bytes = blocks * 128; ops->transform(ctx->state, data, blocks); len -= bytes; total += (bytes) * 8; data += bytes; } memcpy(m + pos, data, len); pos += len; total += len * 8; ctx->count[0] = pos; ctx->count[1] = total; } static void sha256_final(sha256_ctx *ctx, uint8_t *result, int bits) { uint64_t mlen, pos = ctx->count[0]; uint8_t *m = ctx->wbuf; uint32_t *R = (uint32_t *)result; const sha256_ops_t *ops = ctx->ops; m[pos++] = 0x80; if (pos > 56) { memset(m + pos, 0, 64 - pos); ops->transform(ctx->state, m, 1); pos = 0; } memset(m + pos, 0, 64 - pos); mlen = BE_64(ctx->count[1]); memcpy(m + (64 - 8), &mlen, 64 / 8); ops->transform(ctx->state, m, 1); switch (bits) { case 224: /* 28 - unused currently /TR */ R[0] = BE_32(ctx->state[0]); R[1] = BE_32(ctx->state[1]); R[2] = BE_32(ctx->state[2]); R[3] = BE_32(ctx->state[3]); R[4] = BE_32(ctx->state[4]); R[5] = BE_32(ctx->state[5]); R[6] = BE_32(ctx->state[6]); break; case 256: /* 32 */ R[0] = BE_32(ctx->state[0]); R[1] = BE_32(ctx->state[1]); R[2] = BE_32(ctx->state[2]); R[3] = BE_32(ctx->state[3]); R[4] = BE_32(ctx->state[4]); R[5] = BE_32(ctx->state[5]); R[6] = BE_32(ctx->state[6]); R[7] = BE_32(ctx->state[7]); break; } memset(ctx, 0, sizeof (*ctx)); } static void sha512_final(sha512_ctx *ctx, uint8_t *result, int bits) { uint64_t mlen, pos = ctx->count[0]; uint8_t *m = ctx->wbuf, *r; uint64_t *R = (uint64_t *)result; const sha512_ops_t *ops = ctx->ops; m[pos++] = 0x80; if (pos > 112) { memset(m + pos, 0, 128 - pos); ops->transform(ctx->state, m, 1); pos = 0; } memset(m + pos, 0, 128 - pos); mlen = BE_64(ctx->count[1]); memcpy(m + (128 - 8), &mlen, 64 / 8); ops->transform(ctx->state, m, 1); switch (bits) { case 224: /* 28 => 3,5 x 8 */ r = result + 24; R[0] = BE_64(ctx->state[0]); R[1] = BE_64(ctx->state[1]); R[2] = BE_64(ctx->state[2]); /* last 4 bytes are special here */ *r++ = (uint8_t)(ctx->state[3] >> 56); *r++ = (uint8_t)(ctx->state[3] >> 48); *r++ = (uint8_t)(ctx->state[3] >> 40); *r++ = (uint8_t)(ctx->state[3] >> 32); break; case 256: /* 32 */ R[0] = BE_64(ctx->state[0]); R[1] = BE_64(ctx->state[1]); R[2] = BE_64(ctx->state[2]); R[3] = BE_64(ctx->state[3]); break; case 384: /* 48 */ R[0] = BE_64(ctx->state[0]); R[1] = BE_64(ctx->state[1]); R[2] = BE_64(ctx->state[2]); R[3] = BE_64(ctx->state[3]); R[4] = BE_64(ctx->state[4]); R[5] = BE_64(ctx->state[5]); break; case 512: /* 64 */ R[0] = BE_64(ctx->state[0]); R[1] = BE_64(ctx->state[1]); R[2] = BE_64(ctx->state[2]); R[3] = BE_64(ctx->state[3]); R[4] = BE_64(ctx->state[4]); R[5] = BE_64(ctx->state[5]); R[6] = BE_64(ctx->state[6]); R[7] = BE_64(ctx->state[7]); break; } memset(ctx, 0, sizeof (*ctx)); } /* SHA2 Init function */ void SHA2Init(int algotype, SHA2_CTX *ctx) { sha256_ctx *ctx256 = &ctx->sha256; sha512_ctx *ctx512 = &ctx->sha512; - ASSERT3S(algotype, >=, SHA256_MECH_INFO_TYPE); - ASSERT3S(algotype, <=, SHA512_256_MECH_INFO_TYPE); + ASSERT3S(algotype, >=, SHA256_HMAC_MECH_INFO_TYPE); + ASSERT3S(algotype, <=, SHA512_256); memset(ctx, 0, sizeof (*ctx)); ctx->algotype = algotype; switch (ctx->algotype) { - case SHA256_MECH_INFO_TYPE: + case SHA256: case SHA256_HMAC_MECH_INFO_TYPE: case SHA256_HMAC_GEN_MECH_INFO_TYPE: ctx256->state[0] = 0x6a09e667; ctx256->state[1] = 0xbb67ae85; ctx256->state[2] = 0x3c6ef372; ctx256->state[3] = 0xa54ff53a; ctx256->state[4] = 0x510e527f; ctx256->state[5] = 0x9b05688c; ctx256->state[6] = 0x1f83d9ab; ctx256->state[7] = 0x5be0cd19; ctx256->count[0] = 0; ctx256->ops = sha256_get_ops(); break; - case SHA384_MECH_INFO_TYPE: case SHA384_HMAC_MECH_INFO_TYPE: case SHA384_HMAC_GEN_MECH_INFO_TYPE: ctx512->state[0] = 0xcbbb9d5dc1059ed8ULL; ctx512->state[1] = 0x629a292a367cd507ULL; ctx512->state[2] = 0x9159015a3070dd17ULL; ctx512->state[3] = 0x152fecd8f70e5939ULL; ctx512->state[4] = 0x67332667ffc00b31ULL; ctx512->state[5] = 0x8eb44a8768581511ULL; ctx512->state[6] = 0xdb0c2e0d64f98fa7ULL; ctx512->state[7] = 0x47b5481dbefa4fa4ULL; ctx512->count[0] = 0; ctx512->count[1] = 0; ctx512->ops = sha512_get_ops(); break; - case SHA512_MECH_INFO_TYPE: + case SHA512: case SHA512_HMAC_MECH_INFO_TYPE: case SHA512_HMAC_GEN_MECH_INFO_TYPE: ctx512->state[0] = 0x6a09e667f3bcc908ULL; ctx512->state[1] = 0xbb67ae8584caa73bULL; ctx512->state[2] = 0x3c6ef372fe94f82bULL; ctx512->state[3] = 0xa54ff53a5f1d36f1ULL; ctx512->state[4] = 0x510e527fade682d1ULL; ctx512->state[5] = 0x9b05688c2b3e6c1fULL; ctx512->state[6] = 0x1f83d9abfb41bd6bULL; ctx512->state[7] = 0x5be0cd19137e2179ULL; ctx512->count[0] = 0; ctx512->count[1] = 0; ctx512->ops = sha512_get_ops(); break; - case SHA512_224_MECH_INFO_TYPE: - ctx512->state[0] = 0x8c3d37c819544da2ULL; - ctx512->state[1] = 0x73e1996689dcd4d6ULL; - ctx512->state[2] = 0x1dfab7ae32ff9c82ULL; - ctx512->state[3] = 0x679dd514582f9fcfULL; - ctx512->state[4] = 0x0f6d2b697bd44da8ULL; - ctx512->state[5] = 0x77e36f7304c48942ULL; - ctx512->state[6] = 0x3f9d85a86a1d36c8ULL; - ctx512->state[7] = 0x1112e6ad91d692a1ULL; - ctx512->count[0] = 0; - ctx512->count[1] = 0; - ctx512->ops = sha512_get_ops(); - break; - case SHA512_256_MECH_INFO_TYPE: + case SHA512_256: ctx512->state[0] = 0x22312194fc2bf72cULL; ctx512->state[1] = 0x9f555fa3c84c64c2ULL; ctx512->state[2] = 0x2393b86b6f53b151ULL; ctx512->state[3] = 0x963877195940eabdULL; ctx512->state[4] = 0x96283ee2a88effe3ULL; ctx512->state[5] = 0xbe5e1e2553863992ULL; ctx512->state[6] = 0x2b0199fc2c85b8aaULL; ctx512->state[7] = 0x0eb72ddc81c52ca2ULL; ctx512->count[0] = 0; ctx512->count[1] = 0; ctx512->ops = sha512_get_ops(); break; } } /* SHA2 Update function */ void SHA2Update(SHA2_CTX *ctx, const void *data, size_t len) { /* check for zero input length */ if (len == 0) return; ASSERT3P(data, !=, NULL); switch (ctx->algotype) { - case SHA256_MECH_INFO_TYPE: + case SHA256: case SHA256_HMAC_MECH_INFO_TYPE: case SHA256_HMAC_GEN_MECH_INFO_TYPE: sha256_update(&ctx->sha256, data, len); break; - case SHA384_MECH_INFO_TYPE: case SHA384_HMAC_MECH_INFO_TYPE: case SHA384_HMAC_GEN_MECH_INFO_TYPE: sha512_update(&ctx->sha512, data, len); break; - case SHA512_MECH_INFO_TYPE: + case SHA512: case SHA512_HMAC_MECH_INFO_TYPE: case SHA512_HMAC_GEN_MECH_INFO_TYPE: sha512_update(&ctx->sha512, data, len); break; - case SHA512_224_MECH_INFO_TYPE: - sha512_update(&ctx->sha512, data, len); - break; - case SHA512_256_MECH_INFO_TYPE: + case SHA512_256: sha512_update(&ctx->sha512, data, len); break; } } /* SHA2Final function */ void SHA2Final(void *digest, SHA2_CTX *ctx) { switch (ctx->algotype) { - case SHA256_MECH_INFO_TYPE: + case SHA256: case SHA256_HMAC_MECH_INFO_TYPE: case SHA256_HMAC_GEN_MECH_INFO_TYPE: sha256_final(&ctx->sha256, digest, 256); break; - case SHA384_MECH_INFO_TYPE: case SHA384_HMAC_MECH_INFO_TYPE: case SHA384_HMAC_GEN_MECH_INFO_TYPE: sha512_final(&ctx->sha512, digest, 384); break; - case SHA512_MECH_INFO_TYPE: + case SHA512: case SHA512_HMAC_MECH_INFO_TYPE: case SHA512_HMAC_GEN_MECH_INFO_TYPE: sha512_final(&ctx->sha512, digest, 512); break; - case SHA512_224_MECH_INFO_TYPE: - sha512_final(&ctx->sha512, digest, 224); - break; - case SHA512_256_MECH_INFO_TYPE: + case SHA512_256: sha512_final(&ctx->sha512, digest, 256); break; } } /* the generic implementation is always okay */ static boolean_t sha2_is_supported(void) { return (B_TRUE); } const sha256_ops_t sha256_generic_impl = { .name = "generic", .transform = sha256_generic, .is_supported = sha2_is_supported }; const sha512_ops_t sha512_generic_impl = { .name = "generic", .transform = sha512_generic, .is_supported = sha2_is_supported }; diff --git a/module/icp/io/sha2_mod.c b/module/icp/io/sha2_mod.c index c8e3b4fccdd1..d80ea1e677b1 100644 --- a/module/icp/io/sha2_mod.c +++ b/module/icp/io/sha2_mod.c @@ -1,1012 +1,1006 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or https://opensource.org/licenses/CDDL-1.0. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include /* * Macros to access the SHA2 or SHA2-HMAC contexts from a context passed * by KCF to one of the entry points. */ #define PROV_SHA2_CTX(ctx) ((sha2_ctx_t *)(ctx)->cc_provider_private) #define PROV_SHA2_HMAC_CTX(ctx) ((sha2_hmac_ctx_t *)(ctx)->cc_provider_private) /* to extract the digest length passed as mechanism parameter */ #define PROV_SHA2_GET_DIGEST_LEN(m, len) { \ if (IS_P2ALIGNED((m)->cm_param, sizeof (ulong_t))) \ (len) = (uint32_t)*((ulong_t *)(m)->cm_param); \ else { \ ulong_t tmp_ulong; \ memcpy(&tmp_ulong, (m)->cm_param, sizeof (ulong_t)); \ (len) = (uint32_t)tmp_ulong; \ } \ } #define PROV_SHA2_DIGEST_KEY(mech, ctx, key, len, digest) { \ SHA2Init(mech, ctx); \ SHA2Update(ctx, key, len); \ SHA2Final(digest, ctx); \ } /* * Mechanism info structure passed to KCF during registration. */ static const crypto_mech_info_t sha2_mech_info_tab[] = { - /* SHA256 */ - {SUN_CKM_SHA256, SHA256_MECH_INFO_TYPE, 0}, /* SHA256-HMAC */ {SUN_CKM_SHA256_HMAC, SHA256_HMAC_MECH_INFO_TYPE, CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC}, /* SHA256-HMAC GENERAL */ {SUN_CKM_SHA256_HMAC_GENERAL, SHA256_HMAC_GEN_MECH_INFO_TYPE, CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC}, - /* SHA384 */ - {SUN_CKM_SHA384, SHA384_MECH_INFO_TYPE, 0}, /* SHA384-HMAC */ {SUN_CKM_SHA384_HMAC, SHA384_HMAC_MECH_INFO_TYPE, CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC}, /* SHA384-HMAC GENERAL */ {SUN_CKM_SHA384_HMAC_GENERAL, SHA384_HMAC_GEN_MECH_INFO_TYPE, CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC}, - /* SHA512 */ - {SUN_CKM_SHA512, SHA512_MECH_INFO_TYPE, 0}, /* SHA512-HMAC */ {SUN_CKM_SHA512_HMAC, SHA512_HMAC_MECH_INFO_TYPE, CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC}, /* SHA512-HMAC GENERAL */ {SUN_CKM_SHA512_HMAC_GENERAL, SHA512_HMAC_GEN_MECH_INFO_TYPE, CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC}, }; static int sha2_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t); static int sha2_mac_update(crypto_ctx_t *, crypto_data_t *); static int sha2_mac_final(crypto_ctx_t *, crypto_data_t *); static int sha2_mac_atomic(crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t); static int sha2_mac_verify_atomic(crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t); static const crypto_mac_ops_t sha2_mac_ops = { .mac_init = sha2_mac_init, .mac = NULL, .mac_update = sha2_mac_update, .mac_final = sha2_mac_final, .mac_atomic = sha2_mac_atomic, .mac_verify_atomic = sha2_mac_verify_atomic }; static int sha2_create_ctx_template(crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *, size_t *); static int sha2_free_context(crypto_ctx_t *); static const crypto_ctx_ops_t sha2_ctx_ops = { .create_ctx_template = sha2_create_ctx_template, .free_context = sha2_free_context }; static const crypto_ops_t sha2_crypto_ops = { NULL, &sha2_mac_ops, &sha2_ctx_ops, }; static const crypto_provider_info_t sha2_prov_info = { "SHA2 Software Provider", &sha2_crypto_ops, sizeof (sha2_mech_info_tab) / sizeof (crypto_mech_info_t), sha2_mech_info_tab }; static crypto_kcf_provider_handle_t sha2_prov_handle = 0; int sha2_mod_init(void) { int ret; /* * Register with KCF. If the registration fails, log an * error but do not uninstall the module, since the functionality * provided by misc/sha2 should still be available. */ if ((ret = crypto_register_provider(&sha2_prov_info, &sha2_prov_handle)) != CRYPTO_SUCCESS) cmn_err(CE_WARN, "sha2 _init: " "crypto_register_provider() failed (0x%x)", ret); return (0); } int sha2_mod_fini(void) { int ret = 0; if (sha2_prov_handle != 0) { if ((ret = crypto_unregister_provider(sha2_prov_handle)) != CRYPTO_SUCCESS) { cmn_err(CE_WARN, "sha2 _fini: crypto_unregister_provider() " "failed (0x%x)", ret); return (EBUSY); } sha2_prov_handle = 0; } return (ret); } /* * Helper SHA2 digest update function for uio data. */ static int sha2_digest_update_uio(SHA2_CTX *sha2_ctx, crypto_data_t *data) { off_t offset = data->cd_offset; size_t length = data->cd_length; uint_t vec_idx = 0; size_t cur_len; /* we support only kernel buffer */ if (zfs_uio_segflg(data->cd_uio) != UIO_SYSSPACE) return (CRYPTO_ARGUMENTS_BAD); /* * Jump to the first iovec containing data to be * digested. */ offset = zfs_uio_index_at_offset(data->cd_uio, offset, &vec_idx); if (vec_idx == zfs_uio_iovcnt(data->cd_uio)) { /* * The caller specified an offset that is larger than the * total size of the buffers it provided. */ return (CRYPTO_DATA_LEN_RANGE); } /* * Now do the digesting on the iovecs. */ while (vec_idx < zfs_uio_iovcnt(data->cd_uio) && length > 0) { cur_len = MIN(zfs_uio_iovlen(data->cd_uio, vec_idx) - offset, length); SHA2Update(sha2_ctx, (uint8_t *)zfs_uio_iovbase(data->cd_uio, vec_idx) + offset, cur_len); length -= cur_len; vec_idx++; offset = 0; } if (vec_idx == zfs_uio_iovcnt(data->cd_uio) && length > 0) { /* * The end of the specified iovec's was reached but * the length requested could not be processed, i.e. * The caller requested to digest more data than it provided. */ return (CRYPTO_DATA_LEN_RANGE); } return (CRYPTO_SUCCESS); } /* * Helper SHA2 digest final function for uio data. * digest_len is the length of the desired digest. If digest_len * is smaller than the default SHA2 digest length, the caller * must pass a scratch buffer, digest_scratch, which must * be at least the algorithm's digest length bytes. */ static int sha2_digest_final_uio(SHA2_CTX *sha2_ctx, crypto_data_t *digest, ulong_t digest_len, uchar_t *digest_scratch) { off_t offset = digest->cd_offset; uint_t vec_idx = 0; /* we support only kernel buffer */ if (zfs_uio_segflg(digest->cd_uio) != UIO_SYSSPACE) return (CRYPTO_ARGUMENTS_BAD); /* * Jump to the first iovec containing ptr to the digest to * be returned. */ offset = zfs_uio_index_at_offset(digest->cd_uio, offset, &vec_idx); if (vec_idx == zfs_uio_iovcnt(digest->cd_uio)) { /* * The caller specified an offset that is * larger than the total size of the buffers * it provided. */ return (CRYPTO_DATA_LEN_RANGE); } if (offset + digest_len <= zfs_uio_iovlen(digest->cd_uio, vec_idx)) { /* * The computed SHA2 digest will fit in the current * iovec. */ if (((sha2_ctx->algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) && (digest_len != SHA256_DIGEST_LENGTH)) || ((sha2_ctx->algotype > SHA256_HMAC_GEN_MECH_INFO_TYPE) && (digest_len != SHA512_DIGEST_LENGTH))) { /* * The caller requested a short digest. Digest * into a scratch buffer and return to * the user only what was requested. */ SHA2Final(digest_scratch, sha2_ctx); memcpy((uchar_t *) zfs_uio_iovbase(digest->cd_uio, vec_idx) + offset, digest_scratch, digest_len); } else { SHA2Final((uchar_t *)zfs_uio_iovbase(digest-> cd_uio, vec_idx) + offset, sha2_ctx); } } else { /* * The computed digest will be crossing one or more iovec's. * This is bad performance-wise but we need to support it. * Allocate a small scratch buffer on the stack and * copy it piece meal to the specified digest iovec's. */ uchar_t digest_tmp[SHA512_DIGEST_LENGTH]; off_t scratch_offset = 0; size_t length = digest_len; size_t cur_len; SHA2Final(digest_tmp, sha2_ctx); while (vec_idx < zfs_uio_iovcnt(digest->cd_uio) && length > 0) { cur_len = MIN(zfs_uio_iovlen(digest->cd_uio, vec_idx) - offset, length); memcpy( zfs_uio_iovbase(digest->cd_uio, vec_idx) + offset, digest_tmp + scratch_offset, cur_len); length -= cur_len; vec_idx++; scratch_offset += cur_len; offset = 0; } if (vec_idx == zfs_uio_iovcnt(digest->cd_uio) && length > 0) { /* * The end of the specified iovec's was reached but * the length requested could not be processed, i.e. * The caller requested to digest more data than it * provided. */ return (CRYPTO_DATA_LEN_RANGE); } } return (CRYPTO_SUCCESS); } /* * KCF software provider mac entry points. * * SHA2 HMAC is: SHA2(key XOR opad, SHA2(key XOR ipad, text)) * * Init: * The initialization routine initializes what we denote * as the inner and outer contexts by doing * - for inner context: SHA2(key XOR ipad) * - for outer context: SHA2(key XOR opad) * * Update: * Each subsequent SHA2 HMAC update will result in an * update of the inner context with the specified data. * * Final: * The SHA2 HMAC final will do a SHA2 final operation on the * inner context, and the resulting digest will be used * as the data for an update on the outer context. Last * but not least, a SHA2 final on the outer context will * be performed to obtain the SHA2 HMAC digest to return * to the user. */ /* * Initialize a SHA2-HMAC context. */ static void sha2_mac_init_ctx(sha2_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes) { uint64_t ipad[SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t)] = {0}; uint64_t opad[SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t)] = {0}; int i, block_size, blocks_per_int64; /* Determine the block size */ if (ctx->hc_mech_type <= SHA256_HMAC_GEN_MECH_INFO_TYPE) { block_size = SHA256_HMAC_BLOCK_SIZE; blocks_per_int64 = SHA256_HMAC_BLOCK_SIZE / sizeof (uint64_t); } else { block_size = SHA512_HMAC_BLOCK_SIZE; blocks_per_int64 = SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t); } (void) memset(ipad, 0, block_size); (void) memset(opad, 0, block_size); if (keyval != NULL) { (void) memcpy(ipad, keyval, length_in_bytes); (void) memcpy(opad, keyval, length_in_bytes); } else { ASSERT0(length_in_bytes); } /* XOR key with ipad (0x36) and opad (0x5c) */ for (i = 0; i < blocks_per_int64; i ++) { ipad[i] ^= 0x3636363636363636; opad[i] ^= 0x5c5c5c5c5c5c5c5c; } /* perform SHA2 on ipad */ SHA2Init(ctx->hc_mech_type, &ctx->hc_icontext); SHA2Update(&ctx->hc_icontext, (uint8_t *)ipad, block_size); /* perform SHA2 on opad */ SHA2Init(ctx->hc_mech_type, &ctx->hc_ocontext); SHA2Update(&ctx->hc_ocontext, (uint8_t *)opad, block_size); } /* */ static int sha2_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, crypto_key_t *key, crypto_spi_ctx_template_t ctx_template) { int ret = CRYPTO_SUCCESS; uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); uint_t sha_digest_len, sha_hmac_block_size; /* * Set the digest length and block size to values appropriate to the * mechanism */ switch (mechanism->cm_type) { case SHA256_HMAC_MECH_INFO_TYPE: case SHA256_HMAC_GEN_MECH_INFO_TYPE: sha_digest_len = SHA256_DIGEST_LENGTH; sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE; break; case SHA384_HMAC_MECH_INFO_TYPE: case SHA384_HMAC_GEN_MECH_INFO_TYPE: case SHA512_HMAC_MECH_INFO_TYPE: case SHA512_HMAC_GEN_MECH_INFO_TYPE: sha_digest_len = SHA512_DIGEST_LENGTH; sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE; break; default: return (CRYPTO_MECHANISM_INVALID); } ctx->cc_provider_private = kmem_alloc(sizeof (sha2_hmac_ctx_t), KM_SLEEP); if (ctx->cc_provider_private == NULL) return (CRYPTO_HOST_MEMORY); PROV_SHA2_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type; if (ctx_template != NULL) { /* reuse context template */ memcpy(PROV_SHA2_HMAC_CTX(ctx), ctx_template, sizeof (sha2_hmac_ctx_t)); } else { /* no context template, compute context */ if (keylen_in_bytes > sha_hmac_block_size) { uchar_t digested_key[SHA512_DIGEST_LENGTH]; sha2_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private; /* * Hash the passed-in key to get a smaller key. * The inner context is used since it hasn't been * initialized yet. */ PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3, &hmac_ctx->hc_icontext, key->ck_data, keylen_in_bytes, digested_key); sha2_mac_init_ctx(PROV_SHA2_HMAC_CTX(ctx), digested_key, sha_digest_len); } else { sha2_mac_init_ctx(PROV_SHA2_HMAC_CTX(ctx), key->ck_data, keylen_in_bytes); } } /* * Get the mechanism parameters, if applicable. */ if (mechanism->cm_type % 3 == 2) { if (mechanism->cm_param == NULL || mechanism->cm_param_len != sizeof (ulong_t)) { ret = CRYPTO_MECHANISM_PARAM_INVALID; } else { PROV_SHA2_GET_DIGEST_LEN(mechanism, PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len); if (PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len > sha_digest_len) ret = CRYPTO_MECHANISM_PARAM_INVALID; } } if (ret != CRYPTO_SUCCESS) { memset(ctx->cc_provider_private, 0, sizeof (sha2_hmac_ctx_t)); kmem_free(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t)); ctx->cc_provider_private = NULL; } return (ret); } static int sha2_mac_update(crypto_ctx_t *ctx, crypto_data_t *data) { int ret = CRYPTO_SUCCESS; ASSERT(ctx->cc_provider_private != NULL); /* * Do a SHA2 update of the inner context using the specified * data. */ switch (data->cd_format) { case CRYPTO_DATA_RAW: SHA2Update(&PROV_SHA2_HMAC_CTX(ctx)->hc_icontext, (uint8_t *)data->cd_raw.iov_base + data->cd_offset, data->cd_length); break; case CRYPTO_DATA_UIO: ret = sha2_digest_update_uio( &PROV_SHA2_HMAC_CTX(ctx)->hc_icontext, data); break; default: ret = CRYPTO_ARGUMENTS_BAD; } return (ret); } static int sha2_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac) { int ret = CRYPTO_SUCCESS; uchar_t digest[SHA512_DIGEST_LENGTH]; uint32_t digest_len, sha_digest_len; ASSERT(ctx->cc_provider_private != NULL); /* Set the digest lengths to values appropriate to the mechanism */ switch (PROV_SHA2_HMAC_CTX(ctx)->hc_mech_type) { case SHA256_HMAC_MECH_INFO_TYPE: sha_digest_len = digest_len = SHA256_DIGEST_LENGTH; break; case SHA384_HMAC_MECH_INFO_TYPE: sha_digest_len = digest_len = SHA384_DIGEST_LENGTH; break; case SHA512_HMAC_MECH_INFO_TYPE: sha_digest_len = digest_len = SHA512_DIGEST_LENGTH; break; case SHA256_HMAC_GEN_MECH_INFO_TYPE: sha_digest_len = SHA256_DIGEST_LENGTH; digest_len = PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len; break; case SHA384_HMAC_GEN_MECH_INFO_TYPE: case SHA512_HMAC_GEN_MECH_INFO_TYPE: sha_digest_len = SHA512_DIGEST_LENGTH; digest_len = PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len; break; default: return (CRYPTO_ARGUMENTS_BAD); } /* * We need to just return the length needed to store the output. * We should not destroy the context for the following cases. */ if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) { mac->cd_length = digest_len; return (CRYPTO_BUFFER_TOO_SMALL); } /* * Do a SHA2 final on the inner context. */ SHA2Final(digest, &PROV_SHA2_HMAC_CTX(ctx)->hc_icontext); /* * Do a SHA2 update on the outer context, feeding the inner * digest as data. */ SHA2Update(&PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext, digest, sha_digest_len); /* * Do a SHA2 final on the outer context, storing the computing * digest in the users buffer. */ switch (mac->cd_format) { case CRYPTO_DATA_RAW: if (digest_len != sha_digest_len) { /* * The caller requested a short digest. Digest * into a scratch buffer and return to * the user only what was requested. */ SHA2Final(digest, &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext); memcpy((unsigned char *)mac->cd_raw.iov_base + mac->cd_offset, digest, digest_len); } else { SHA2Final((unsigned char *)mac->cd_raw.iov_base + mac->cd_offset, &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext); } break; case CRYPTO_DATA_UIO: ret = sha2_digest_final_uio( &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext, mac, digest_len, digest); break; default: ret = CRYPTO_ARGUMENTS_BAD; } if (ret == CRYPTO_SUCCESS) mac->cd_length = digest_len; else mac->cd_length = 0; memset(ctx->cc_provider_private, 0, sizeof (sha2_hmac_ctx_t)); kmem_free(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t)); ctx->cc_provider_private = NULL; return (ret); } #define SHA2_MAC_UPDATE(data, ctx, ret) { \ switch (data->cd_format) { \ case CRYPTO_DATA_RAW: \ SHA2Update(&(ctx).hc_icontext, \ (uint8_t *)data->cd_raw.iov_base + \ data->cd_offset, data->cd_length); \ break; \ case CRYPTO_DATA_UIO: \ ret = sha2_digest_update_uio(&(ctx).hc_icontext, data); \ break; \ default: \ ret = CRYPTO_ARGUMENTS_BAD; \ } \ } static int sha2_mac_atomic(crypto_mechanism_t *mechanism, crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, crypto_spi_ctx_template_t ctx_template) { int ret = CRYPTO_SUCCESS; uchar_t digest[SHA512_DIGEST_LENGTH]; sha2_hmac_ctx_t sha2_hmac_ctx; uint32_t sha_digest_len, digest_len, sha_hmac_block_size; uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); /* * Set the digest length and block size to values appropriate to the * mechanism */ switch (mechanism->cm_type) { case SHA256_HMAC_MECH_INFO_TYPE: case SHA256_HMAC_GEN_MECH_INFO_TYPE: sha_digest_len = digest_len = SHA256_DIGEST_LENGTH; sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE; break; case SHA384_HMAC_MECH_INFO_TYPE: case SHA384_HMAC_GEN_MECH_INFO_TYPE: case SHA512_HMAC_MECH_INFO_TYPE: case SHA512_HMAC_GEN_MECH_INFO_TYPE: sha_digest_len = digest_len = SHA512_DIGEST_LENGTH; sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE; break; default: return (CRYPTO_MECHANISM_INVALID); } if (ctx_template != NULL) { /* reuse context template */ memcpy(&sha2_hmac_ctx, ctx_template, sizeof (sha2_hmac_ctx_t)); } else { sha2_hmac_ctx.hc_mech_type = mechanism->cm_type; /* no context template, initialize context */ if (keylen_in_bytes > sha_hmac_block_size) { /* * Hash the passed-in key to get a smaller key. * The inner context is used since it hasn't been * initialized yet. */ PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3, &sha2_hmac_ctx.hc_icontext, key->ck_data, keylen_in_bytes, digest); sha2_mac_init_ctx(&sha2_hmac_ctx, digest, sha_digest_len); } else { sha2_mac_init_ctx(&sha2_hmac_ctx, key->ck_data, keylen_in_bytes); } } /* get the mechanism parameters, if applicable */ if ((mechanism->cm_type % 3) == 2) { if (mechanism->cm_param == NULL || mechanism->cm_param_len != sizeof (ulong_t)) { ret = CRYPTO_MECHANISM_PARAM_INVALID; goto bail; } PROV_SHA2_GET_DIGEST_LEN(mechanism, digest_len); if (digest_len > sha_digest_len) { ret = CRYPTO_MECHANISM_PARAM_INVALID; goto bail; } } /* do a SHA2 update of the inner context using the specified data */ SHA2_MAC_UPDATE(data, sha2_hmac_ctx, ret); if (ret != CRYPTO_SUCCESS) /* the update failed, free context and bail */ goto bail; /* * Do a SHA2 final on the inner context. */ SHA2Final(digest, &sha2_hmac_ctx.hc_icontext); /* * Do an SHA2 update on the outer context, feeding the inner * digest as data. * * HMAC-SHA384 needs special handling as the outer hash needs only 48 * bytes of the inner hash value. */ if (mechanism->cm_type == SHA384_HMAC_MECH_INFO_TYPE || mechanism->cm_type == SHA384_HMAC_GEN_MECH_INFO_TYPE) SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, SHA384_DIGEST_LENGTH); else SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, sha_digest_len); /* * Do a SHA2 final on the outer context, storing the computed * digest in the users buffer. */ switch (mac->cd_format) { case CRYPTO_DATA_RAW: if (digest_len != sha_digest_len) { /* * The caller requested a short digest. Digest * into a scratch buffer and return to * the user only what was requested. */ SHA2Final(digest, &sha2_hmac_ctx.hc_ocontext); memcpy((unsigned char *)mac->cd_raw.iov_base + mac->cd_offset, digest, digest_len); } else { SHA2Final((unsigned char *)mac->cd_raw.iov_base + mac->cd_offset, &sha2_hmac_ctx.hc_ocontext); } break; case CRYPTO_DATA_UIO: ret = sha2_digest_final_uio(&sha2_hmac_ctx.hc_ocontext, mac, digest_len, digest); break; default: ret = CRYPTO_ARGUMENTS_BAD; } if (ret == CRYPTO_SUCCESS) { mac->cd_length = digest_len; return (CRYPTO_SUCCESS); } bail: memset(&sha2_hmac_ctx, 0, sizeof (sha2_hmac_ctx_t)); mac->cd_length = 0; return (ret); } static int sha2_mac_verify_atomic(crypto_mechanism_t *mechanism, crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, crypto_spi_ctx_template_t ctx_template) { int ret = CRYPTO_SUCCESS; uchar_t digest[SHA512_DIGEST_LENGTH]; sha2_hmac_ctx_t sha2_hmac_ctx; uint32_t sha_digest_len, digest_len, sha_hmac_block_size; uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); /* * Set the digest length and block size to values appropriate to the * mechanism */ switch (mechanism->cm_type) { case SHA256_HMAC_MECH_INFO_TYPE: case SHA256_HMAC_GEN_MECH_INFO_TYPE: sha_digest_len = digest_len = SHA256_DIGEST_LENGTH; sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE; break; case SHA384_HMAC_MECH_INFO_TYPE: case SHA384_HMAC_GEN_MECH_INFO_TYPE: case SHA512_HMAC_MECH_INFO_TYPE: case SHA512_HMAC_GEN_MECH_INFO_TYPE: sha_digest_len = digest_len = SHA512_DIGEST_LENGTH; sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE; break; default: return (CRYPTO_MECHANISM_INVALID); } if (ctx_template != NULL) { /* reuse context template */ memcpy(&sha2_hmac_ctx, ctx_template, sizeof (sha2_hmac_ctx_t)); } else { sha2_hmac_ctx.hc_mech_type = mechanism->cm_type; /* no context template, initialize context */ if (keylen_in_bytes > sha_hmac_block_size) { /* * Hash the passed-in key to get a smaller key. * The inner context is used since it hasn't been * initialized yet. */ PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3, &sha2_hmac_ctx.hc_icontext, key->ck_data, keylen_in_bytes, digest); sha2_mac_init_ctx(&sha2_hmac_ctx, digest, sha_digest_len); } else { sha2_mac_init_ctx(&sha2_hmac_ctx, key->ck_data, keylen_in_bytes); } } /* get the mechanism parameters, if applicable */ if (mechanism->cm_type % 3 == 2) { if (mechanism->cm_param == NULL || mechanism->cm_param_len != sizeof (ulong_t)) { ret = CRYPTO_MECHANISM_PARAM_INVALID; goto bail; } PROV_SHA2_GET_DIGEST_LEN(mechanism, digest_len); if (digest_len > sha_digest_len) { ret = CRYPTO_MECHANISM_PARAM_INVALID; goto bail; } } if (mac->cd_length != digest_len) { ret = CRYPTO_INVALID_MAC; goto bail; } /* do a SHA2 update of the inner context using the specified data */ SHA2_MAC_UPDATE(data, sha2_hmac_ctx, ret); if (ret != CRYPTO_SUCCESS) /* the update failed, free context and bail */ goto bail; /* do a SHA2 final on the inner context */ SHA2Final(digest, &sha2_hmac_ctx.hc_icontext); /* * Do an SHA2 update on the outer context, feeding the inner * digest as data. * * HMAC-SHA384 needs special handling as the outer hash needs only 48 * bytes of the inner hash value. */ if (mechanism->cm_type == SHA384_HMAC_MECH_INFO_TYPE || mechanism->cm_type == SHA384_HMAC_GEN_MECH_INFO_TYPE) SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, SHA384_DIGEST_LENGTH); else SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, sha_digest_len); /* * Do a SHA2 final on the outer context, storing the computed * digest in the users buffer. */ SHA2Final(digest, &sha2_hmac_ctx.hc_ocontext); /* * Compare the computed digest against the expected digest passed * as argument. */ switch (mac->cd_format) { case CRYPTO_DATA_RAW: if (memcmp(digest, (unsigned char *)mac->cd_raw.iov_base + mac->cd_offset, digest_len) != 0) ret = CRYPTO_INVALID_MAC; break; case CRYPTO_DATA_UIO: { off_t offset = mac->cd_offset; uint_t vec_idx = 0; off_t scratch_offset = 0; size_t length = digest_len; size_t cur_len; /* we support only kernel buffer */ if (zfs_uio_segflg(mac->cd_uio) != UIO_SYSSPACE) return (CRYPTO_ARGUMENTS_BAD); /* jump to the first iovec containing the expected digest */ offset = zfs_uio_index_at_offset(mac->cd_uio, offset, &vec_idx); if (vec_idx == zfs_uio_iovcnt(mac->cd_uio)) { /* * The caller specified an offset that is * larger than the total size of the buffers * it provided. */ ret = CRYPTO_DATA_LEN_RANGE; break; } /* do the comparison of computed digest vs specified one */ while (vec_idx < zfs_uio_iovcnt(mac->cd_uio) && length > 0) { cur_len = MIN(zfs_uio_iovlen(mac->cd_uio, vec_idx) - offset, length); if (memcmp(digest + scratch_offset, zfs_uio_iovbase(mac->cd_uio, vec_idx) + offset, cur_len) != 0) { ret = CRYPTO_INVALID_MAC; break; } length -= cur_len; vec_idx++; scratch_offset += cur_len; offset = 0; } break; } default: ret = CRYPTO_ARGUMENTS_BAD; } return (ret); bail: memset(&sha2_hmac_ctx, 0, sizeof (sha2_hmac_ctx_t)); mac->cd_length = 0; return (ret); } /* * KCF software provider context management entry points. */ static int sha2_create_ctx_template(crypto_mechanism_t *mechanism, crypto_key_t *key, crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size) { sha2_hmac_ctx_t *sha2_hmac_ctx_tmpl; uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); uint32_t sha_digest_len, sha_hmac_block_size; /* * Set the digest length and block size to values appropriate to the * mechanism */ switch (mechanism->cm_type) { case SHA256_HMAC_MECH_INFO_TYPE: case SHA256_HMAC_GEN_MECH_INFO_TYPE: sha_digest_len = SHA256_DIGEST_LENGTH; sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE; break; case SHA384_HMAC_MECH_INFO_TYPE: case SHA384_HMAC_GEN_MECH_INFO_TYPE: case SHA512_HMAC_MECH_INFO_TYPE: case SHA512_HMAC_GEN_MECH_INFO_TYPE: sha_digest_len = SHA512_DIGEST_LENGTH; sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE; break; default: return (CRYPTO_MECHANISM_INVALID); } /* * Allocate and initialize SHA2 context. */ sha2_hmac_ctx_tmpl = kmem_alloc(sizeof (sha2_hmac_ctx_t), KM_SLEEP); if (sha2_hmac_ctx_tmpl == NULL) return (CRYPTO_HOST_MEMORY); sha2_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type; if (keylen_in_bytes > sha_hmac_block_size) { uchar_t digested_key[SHA512_DIGEST_LENGTH]; /* * Hash the passed-in key to get a smaller key. * The inner context is used since it hasn't been * initialized yet. */ PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3, &sha2_hmac_ctx_tmpl->hc_icontext, key->ck_data, keylen_in_bytes, digested_key); sha2_mac_init_ctx(sha2_hmac_ctx_tmpl, digested_key, sha_digest_len); } else { sha2_mac_init_ctx(sha2_hmac_ctx_tmpl, key->ck_data, keylen_in_bytes); } *ctx_template = (crypto_spi_ctx_template_t)sha2_hmac_ctx_tmpl; *ctx_template_size = sizeof (sha2_hmac_ctx_t); return (CRYPTO_SUCCESS); } static int sha2_free_context(crypto_ctx_t *ctx) { uint_t ctx_len; if (ctx->cc_provider_private == NULL) return (CRYPTO_SUCCESS); /* * We have to free either SHA2 or SHA2-HMAC contexts, which * have different lengths. * * Note: Below is dependent on the mechanism ordering. */ if (PROV_SHA2_CTX(ctx)->sc_mech_type % 3 == 0) ctx_len = sizeof (sha2_ctx_t); else ctx_len = sizeof (sha2_hmac_ctx_t); memset(ctx->cc_provider_private, 0, ctx_len); kmem_free(ctx->cc_provider_private, ctx_len); ctx->cc_provider_private = NULL; return (CRYPTO_SUCCESS); } diff --git a/tests/zfs-tests/cmd/checksum/sha2_test.c b/tests/zfs-tests/cmd/checksum/sha2_test.c index efcf812d7749..d36b670db8ba 100644 --- a/tests/zfs-tests/cmd/checksum/sha2_test.c +++ b/tests/zfs-tests/cmd/checksum/sha2_test.c @@ -1,264 +1,214 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://opensource.org/licenses/CDDL-1.0. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2013 Saso Kiselkov. All rights reserved. */ /* * This is just to keep the compiler happy about sys/time.h not declaring * gettimeofday due to -D_KERNEL (we can do this since we're actually * running in userspace, but we need -D_KERNEL for the remaining SHA2 code). */ #include #include #include #include #include #include #include #include /* * Test messages from: * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf */ static const char *test_msg0 = "abc"; static const char *test_msg1 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklm" "nlmnomnopnopq"; static const char *test_msg2 = "abcdefghbcdefghicdefghijdefghijkefghijklfgh" "ijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; /* * Test digests from: * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf */ static const uint8_t sha256_test_digests[][32] = { { /* for test_msg0 */ 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23, 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD }, { /* for test_msg1 */ 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8, 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39, 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67, 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 } /* no test vector for test_msg2 */ }; -static const uint8_t sha384_test_digests[][48] = { - { - /* for test_msg0 */ - 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B, - 0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07, - 0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63, - 0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED, - 0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23, - 0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7 - }, - { - /* no test vector for test_msg1 */ - 0 - }, - { - /* for test_msg2 */ - 0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8, - 0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47, - 0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2, - 0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12, - 0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9, - 0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39 - } -}; - static const uint8_t sha512_test_digests[][64] = { { /* for test_msg0 */ 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, 0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31, 0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2, 0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A, 0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8, 0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD, 0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E, 0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F }, { /* no test vector for test_msg1 */ 0 }, { /* for test_msg2 */ 0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA, 0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F, 0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1, 0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18, 0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4, 0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A, 0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54, 0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09 } }; -static const uint8_t sha512_224_test_digests[][28] = { - { - /* for test_msg0 */ - 0x46, 0x34, 0x27, 0x0F, 0x70, 0x7B, 0x6A, 0x54, - 0xDA, 0xAE, 0x75, 0x30, 0x46, 0x08, 0x42, 0xE2, - 0x0E, 0x37, 0xED, 0x26, 0x5C, 0xEE, 0xE9, 0xA4, - 0x3E, 0x89, 0x24, 0xAA - }, - { - /* no test vector for test_msg1 */ - 0 - }, - { - /* for test_msg2 */ - 0x23, 0xFE, 0xC5, 0xBB, 0x94, 0xD6, 0x0B, 0x23, - 0x30, 0x81, 0x92, 0x64, 0x0B, 0x0C, 0x45, 0x33, - 0x35, 0xD6, 0x64, 0x73, 0x4F, 0xE4, 0x0E, 0x72, - 0x68, 0x67, 0x4A, 0xF9 - } -}; - static const uint8_t sha512_256_test_digests[][32] = { { /* for test_msg0 */ 0x53, 0x04, 0x8E, 0x26, 0x81, 0x94, 0x1E, 0xF9, 0x9B, 0x2E, 0x29, 0xB7, 0x6B, 0x4C, 0x7D, 0xAB, 0xE4, 0xC2, 0xD0, 0xC6, 0x34, 0xFC, 0x6D, 0x46, 0xE0, 0xE2, 0xF1, 0x31, 0x07, 0xE7, 0xAF, 0x23 }, { /* no test vector for test_msg1 */ 0 }, { /* for test_msg2 */ 0x39, 0x28, 0xE1, 0x84, 0xFB, 0x86, 0x90, 0xF8, 0x40, 0xDA, 0x39, 0x88, 0x12, 0x1D, 0x31, 0xBE, 0x65, 0xCB, 0x9D, 0x3E, 0xF8, 0x3E, 0xE6, 0x14, 0x6F, 0xEA, 0xC8, 0x61, 0xE1, 0x9B, 0x56, 0x3A } }; int main(int argc, char *argv[]) { boolean_t failed = B_FALSE; uint64_t cpu_mhz = 0; const zfs_impl_t *sha256 = zfs_impl_get_ops("sha256"); const zfs_impl_t *sha512 = zfs_impl_get_ops("sha512"); uint32_t id; if (argc == 2) cpu_mhz = atoi(argv[1]); if (!sha256) return (1); if (!sha512) return (1); #define SHA2_ALGO_TEST(_m, mode, diglen, testdigest) \ do { \ SHA2_CTX ctx; \ uint8_t digest[diglen / 8]; \ - SHA2Init(SHA ## mode ## _MECH_INFO_TYPE, &ctx); \ + SHA2Init(mode, &ctx); \ SHA2Update(&ctx, _m, strlen(_m)); \ SHA2Final(digest, &ctx); \ (void) printf("SHA%-9sMessage: " #_m \ "\tResult: ", #mode); \ if (memcmp(digest, testdigest, diglen / 8) == 0) { \ (void) printf("OK\n"); \ } else { \ (void) printf("FAILED!\n"); \ failed = B_TRUE; \ } \ } while (0) #define SHA2_PERF_TEST(mode, diglen, name) \ do { \ SHA2_CTX ctx; \ uint8_t digest[diglen / 8]; \ uint8_t block[131072]; \ uint64_t delta; \ double cpb = 0; \ int i; \ struct timeval start, end; \ memset(block, 0, sizeof (block)); \ (void) gettimeofday(&start, NULL); \ - SHA2Init(SHA ## mode ## _MECH_INFO_TYPE, &ctx); \ + SHA2Init(mode, &ctx); \ for (i = 0; i < 8192; i++) \ SHA2Update(&ctx, block, sizeof (block)); \ SHA2Final(digest, &ctx); \ (void) gettimeofday(&end, NULL); \ delta = (end.tv_sec * 1000000llu + end.tv_usec) - \ (start.tv_sec * 1000000llu + start.tv_usec); \ if (cpu_mhz != 0) { \ cpb = (cpu_mhz * 1e6 * ((double)delta / \ 1000000)) / (8192 * 128 * 1024); \ } \ (void) printf("sha%s-%-9s%7llu us (%.02f CPB)\n", #mode,\ name, (u_longlong_t)delta, cpb); \ } while (0) (void) printf("Running algorithm correctness tests:\n"); - SHA2_ALGO_TEST(test_msg0, 256, 256, sha256_test_digests[0]); - SHA2_ALGO_TEST(test_msg1, 256, 256, sha256_test_digests[1]); - SHA2_ALGO_TEST(test_msg0, 384, 384, sha384_test_digests[0]); - SHA2_ALGO_TEST(test_msg2, 384, 384, sha384_test_digests[2]); - SHA2_ALGO_TEST(test_msg0, 512, 512, sha512_test_digests[0]); - SHA2_ALGO_TEST(test_msg2, 512, 512, sha512_test_digests[2]); - SHA2_ALGO_TEST(test_msg0, 512_224, 224, sha512_224_test_digests[0]); - SHA2_ALGO_TEST(test_msg2, 512_224, 224, sha512_224_test_digests[2]); - SHA2_ALGO_TEST(test_msg0, 512_256, 256, sha512_256_test_digests[0]); - SHA2_ALGO_TEST(test_msg2, 512_256, 256, sha512_256_test_digests[2]); + SHA2_ALGO_TEST(test_msg0, SHA256, 256, sha256_test_digests[0]); + SHA2_ALGO_TEST(test_msg1, SHA256, 256, sha256_test_digests[1]); + SHA2_ALGO_TEST(test_msg0, SHA512, 512, sha512_test_digests[0]); + SHA2_ALGO_TEST(test_msg2, SHA512, 512, sha512_test_digests[2]); + SHA2_ALGO_TEST(test_msg0, SHA512_256, 256, sha512_256_test_digests[0]); + SHA2_ALGO_TEST(test_msg2, SHA512_256, 256, sha512_256_test_digests[2]); if (failed) return (1); (void) printf("Running performance tests (hashing 1024 MiB of " "data):\n"); for (id = 0; id < sha256->getcnt(); id++) { sha256->setid(id); const char *name = sha256->getname(); - SHA2_PERF_TEST(256, 256, name); + SHA2_PERF_TEST(SHA256, 256, name); } for (id = 0; id < sha512->getcnt(); id++) { sha512->setid(id); const char *name = sha512->getname(); - SHA2_PERF_TEST(512, 512, name); + SHA2_PERF_TEST(SHA512, 512, name); } return (0); }