Changeset View
Changeset View
Standalone View
Standalone View
tools/tools/crypto/cryptocheck.c
Show First 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, | * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, | ||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | ||||
* THE POSSIBILITY OF SUCH DAMAGES. | * THE POSSIBILITY OF SUCH DAMAGES. | ||||
* | * | ||||
* $FreeBSD$ | * $FreeBSD: head/tools/tools/crypto/cryptocheck.c 331726 2018-03-29 04:14:37Z cem $ | ||||
*/ | */ | ||||
/* | /* | ||||
* A different tool for checking hardware crypto support. Whereas | * A different tool for checking hardware crypto support. Whereas | ||||
* cryptotest is focused on simple performance numbers, this tool is | * cryptotest is focused on simple performance numbers, this tool is | ||||
* focused on correctness. For each crypto operation, it performs the | * focused on correctness. For each crypto operation, it performs the | ||||
* operation once in software via OpenSSL and a second time via | * operation once in software via OpenSSL and a second time via | ||||
* OpenCrypto and compares the results. | * OpenCrypto and compares the results. | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | |||||
#ifndef COP_F_CIPHER_FIRST | #ifndef COP_F_CIPHER_FIRST | ||||
#define COP_F_CIPHER_FIRST 0x0001 /* Cipher before MAC. */ | #define COP_F_CIPHER_FIRST 0x0001 /* Cipher before MAC. */ | ||||
#endif | #endif | ||||
struct alg { | struct alg { | ||||
const char *name; | const char *name; | ||||
int cipher; | int cipher; | ||||
int mac; | int mac; | ||||
enum { T_HASH, T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM } type; | enum { T_HASH, T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM, T_CCM } type; | ||||
const EVP_CIPHER *(*evp_cipher)(void); | const EVP_CIPHER *(*evp_cipher)(void); | ||||
const EVP_MD *(*evp_md)(void); | const EVP_MD *(*evp_md)(void); | ||||
} algs[] = { | } algs[] = { | ||||
{ .name = "sha1", .mac = CRYPTO_SHA1, .type = T_HASH, | { .name = "sha1", .mac = CRYPTO_SHA1, .type = T_HASH, | ||||
.evp_md = EVP_sha1 }, | .evp_md = EVP_sha1 }, | ||||
{ .name = "sha224", .mac = CRYPTO_SHA2_224, .type = T_HASH, | { .name = "sha224", .mac = CRYPTO_SHA2_224, .type = T_HASH, | ||||
.evp_md = EVP_sha224 }, | .evp_md = EVP_sha224 }, | ||||
{ .name = "sha256", .mac = CRYPTO_SHA2_256, .type = T_HASH, | { .name = "sha256", .mac = CRYPTO_SHA2_256, .type = T_HASH, | ||||
Show All 38 Lines | const EVP_MD *(*evp_md)(void); | ||||
.mac = CRYPTO_AES_128_NIST_GMAC, .type = T_GCM, | .mac = CRYPTO_AES_128_NIST_GMAC, .type = T_GCM, | ||||
.evp_cipher = EVP_aes_128_gcm }, | .evp_cipher = EVP_aes_128_gcm }, | ||||
{ .name = "aes-gcm192", .cipher = CRYPTO_AES_NIST_GCM_16, | { .name = "aes-gcm192", .cipher = CRYPTO_AES_NIST_GCM_16, | ||||
.mac = CRYPTO_AES_192_NIST_GMAC, .type = T_GCM, | .mac = CRYPTO_AES_192_NIST_GMAC, .type = T_GCM, | ||||
.evp_cipher = EVP_aes_192_gcm }, | .evp_cipher = EVP_aes_192_gcm }, | ||||
{ .name = "aes-gcm256", .cipher = CRYPTO_AES_NIST_GCM_16, | { .name = "aes-gcm256", .cipher = CRYPTO_AES_NIST_GCM_16, | ||||
.mac = CRYPTO_AES_256_NIST_GMAC, .type = T_GCM, | .mac = CRYPTO_AES_256_NIST_GMAC, .type = T_GCM, | ||||
.evp_cipher = EVP_aes_256_gcm }, | .evp_cipher = EVP_aes_256_gcm }, | ||||
{ .name = "aes-ccm", .cipher = CRYPTO_AES_CCM_16, | |||||
.mac = CRYPTO_AES_128_CCM_CBC_MAC, .type = T_CCM, | |||||
.evp_cipher = EVP_aes_128_ccm }, | |||||
{ .name = "aes-ccm192", .cipher = CRYPTO_AES_CCM_16, | |||||
.mac = CRYPTO_AES_192_CCM_CBC_MAC, .type = T_CCM, | |||||
.evp_cipher = EVP_aes_192_ccm }, | |||||
{ .name = "aes-ccm256", .cipher = CRYPTO_AES_CCM_16, | |||||
.mac = CRYPTO_AES_256_CCM_CBC_MAC, .type = T_CCM, | |||||
.evp_cipher = EVP_aes_256_ccm }, | |||||
}; | }; | ||||
static bool verbose; | static bool verbose; | ||||
static int crid; | static int crid; | ||||
static size_t aad_len; | static size_t aad_len; | ||||
static void | static void | ||||
usage(void) | usage(void) | ||||
▲ Show 20 Lines • Show All 957 Lines • ▼ Show 20 Lines | out: | ||||
free(ciphertext); | free(ciphertext); | ||||
free(buffer); | free(buffer); | ||||
free(cleartext); | free(cleartext); | ||||
free(iv); | free(iv); | ||||
free(key); | free(key); | ||||
} | } | ||||
static void | static void | ||||
openssl_ccm_encrypt(struct alg *alg, const EVP_CIPHER *cipher, const char *key, | |||||
const char *iv, size_t iv_len, const char *aad, size_t aad_len, | |||||
const char *input, char *output, size_t size, char *tag) | |||||
{ | |||||
EVP_CIPHER_CTX *ctx; | |||||
int outl, total; | |||||
ctx = EVP_CIPHER_CTX_new(); | |||||
if (ctx == NULL) | |||||
errx(1, "OpenSSL %s (%zu) ctx new failed: %s", alg->name, | |||||
size, ERR_error_string(ERR_get_error(), NULL)); | |||||
if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1) | |||||
errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name, | |||||
size, ERR_error_string(ERR_get_error(), NULL)); | |||||
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, iv_len, NULL) != 1) | |||||
errx(1, "OpenSSL %s (%zu) setting iv length failed: %s", alg->name, | |||||
size, ERR_error_string(ERR_get_error(), NULL)); | |||||
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, AES_CBC_MAC_HASH_LEN, NULL) != 1) | |||||
errx(1, "OpenSSL %s (%zu) setting tag length failed: %s", alg->name, | |||||
size, ERR_error_string(ERR_get_error(), NULL)); | |||||
if (EVP_EncryptInit_ex(ctx, NULL, NULL, (const u_char *)key, | |||||
(const u_char *)iv) != 1) | |||||
errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name, | |||||
size, ERR_error_string(ERR_get_error(), NULL)); | |||||
if (EVP_EncryptUpdate(ctx, NULL, &outl, NULL, size) != 1) | |||||
errx(1, "OpenSSL %s (%zu) unable to set data length: %s", alg->name, | |||||
size, ERR_error_string(ERR_get_error(), NULL)); | |||||
if (aad != NULL) { | |||||
if (EVP_EncryptUpdate(ctx, NULL, &outl, (const u_char *)aad, | |||||
aad_len) != 1) | |||||
errx(1, "OpenSSL %s (%zu) aad update failed: %s", | |||||
alg->name, size, | |||||
ERR_error_string(ERR_get_error(), NULL)); | |||||
} | |||||
if (EVP_EncryptUpdate(ctx, (u_char *)output, &outl, | |||||
(const u_char *)input, size) != 1) | |||||
errx(1, "OpenSSL %s (%zu) encrypt update failed: %s", alg->name, | |||||
size, ERR_error_string(ERR_get_error(), NULL)); | |||||
total = outl; | |||||
if (EVP_EncryptFinal_ex(ctx, (u_char *)output + outl, &outl) != 1) | |||||
errx(1, "OpenSSL %s (%zu) encrypt final failed: %s", alg->name, | |||||
size, ERR_error_string(ERR_get_error(), NULL)); | |||||
total += outl; | |||||
if (total != size) | |||||
errx(1, "OpenSSL %s (%zu) encrypt size mismatch: %d", alg->name, | |||||
size, total); | |||||
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, AES_CBC_MAC_HASH_LEN, | |||||
tag) != 1) | |||||
errx(1, "OpenSSL %s (%zu) get tag failed: %s", alg->name, | |||||
size, ERR_error_string(ERR_get_error(), NULL)); | |||||
EVP_CIPHER_CTX_free(ctx); | |||||
} | |||||
static bool | |||||
ocf_ccm(struct alg *alg, const char *key, size_t key_len, const char *iv, | |||||
size_t iv_len, const char *aad, size_t aad_len, const char *input, | |||||
char *output, size_t size, char *tag, int enc, int *cridp) | |||||
{ | |||||
struct session2_op sop; | |||||
struct crypt_aead caead; | |||||
int fd; | |||||
memset(&sop, 0, sizeof(sop)); | |||||
memset(&caead, 0, sizeof(caead)); | |||||
sop.crid = crid; | |||||
sop.keylen = key_len; | |||||
sop.key = (char *)key; | |||||
sop.cipher = alg->cipher; | |||||
sop.mackeylen = key_len; | |||||
sop.mackey = (char *)key; | |||||
sop.mac = alg->mac; | |||||
fd = crget(); | |||||
if (ioctl(fd, CIOCGSESSION2, &sop) < 0) { | |||||
warn("cryptodev %s not supported for device %s", | |||||
alg->name, crfind(crid)); | |||||
close(fd); | |||||
return (false); | |||||
} | |||||
caead.ses = sop.ses; | |||||
caead.op = enc ? COP_ENCRYPT : COP_DECRYPT; | |||||
caead.len = size; | |||||
caead.aadlen = aad_len; | |||||
caead.ivlen = iv_len; | |||||
caead.src = (char *)input; | |||||
caead.dst = output; | |||||
caead.aad = (char *)aad; | |||||
caead.tag = tag; | |||||
caead.iv = (char *)iv; | |||||
if (ioctl(fd, CIOCCRYPTAEAD, &caead) < 0) { | |||||
warn("cryptodev %s (%zu) failed for device %s", | |||||
alg->name, size, crfind(crid)); | |||||
close(fd); | |||||
return (false); | |||||
} | |||||
if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0) | |||||
warn("ioctl(CIOCFSESSION)"); | |||||
close(fd); | |||||
*cridp = sop.crid; | |||||
return (true); | |||||
} | |||||
static void | |||||
run_ccm_test(struct alg *alg, size_t size) | |||||
{ | |||||
const EVP_CIPHER *cipher; | |||||
char *aad, *buffer, *cleartext, *ciphertext; | |||||
char *iv, *key; | |||||
u_int iv_len, key_len; | |||||
int crid; | |||||
char control_tag[AES_CBC_MAC_HASH_LEN], test_tag[AES_CBC_MAC_HASH_LEN]; | |||||
cipher = alg->evp_cipher(); | |||||
if (size % EVP_CIPHER_block_size(cipher) != 0) { | |||||
if (verbose) | |||||
printf( | |||||
"%s (%zu): invalid buffer size (block size %d)\n", | |||||
alg->name, size, EVP_CIPHER_block_size(cipher)); | |||||
return; | |||||
} | |||||
memset(control_tag, 0x3c, sizeof(control_tag)); | |||||
memset(test_tag, 0x3c, sizeof(test_tag)); | |||||
key_len = EVP_CIPHER_key_length(cipher); | |||||
iv_len = EVP_CIPHER_iv_length(cipher); | |||||
key = alloc_buffer(key_len); | |||||
iv = generate_iv(iv_len, alg); | |||||
cleartext = alloc_buffer(size); | |||||
buffer = malloc(size); | |||||
ciphertext = malloc(size); | |||||
if (aad_len != 0) | |||||
aad = alloc_buffer(aad_len); | |||||
else | |||||
aad = NULL; | |||||
/* OpenSSL encrypt */ | |||||
openssl_ccm_encrypt(alg, cipher, key, iv, iv_len, aad, aad_len, cleartext, | |||||
ciphertext, size, control_tag); | |||||
/* OCF encrypt */ | |||||
if (!ocf_ccm(alg, key, key_len, iv, iv_len, aad, aad_len, cleartext, | |||||
buffer, size, test_tag, 1, &crid)) | |||||
goto out; | |||||
if (memcmp(ciphertext, buffer, size) != 0) { | |||||
printf("%s (%zu) encryption mismatch:\n", alg->name, size); | |||||
printf("control:\n"); | |||||
hexdump(ciphertext, size, NULL, 0); | |||||
printf("test (cryptodev device %s):\n", crfind(crid)); | |||||
hexdump(buffer, size, NULL, 0); | |||||
goto out; | |||||
} | |||||
if (memcmp(control_tag, test_tag, sizeof(control_tag)) != 0) { | |||||
printf("%s (%zu) enc tag mismatch:\n", alg->name, size); | |||||
printf("control:\n"); | |||||
hexdump(control_tag, sizeof(control_tag), NULL, 0); | |||||
printf("test (cryptodev device %s):\n", crfind(crid)); | |||||
hexdump(test_tag, sizeof(test_tag), NULL, 0); | |||||
goto out; | |||||
} | |||||
/* OCF decrypt */ | |||||
if (!ocf_ccm(alg, key, key_len, iv, iv_len, aad, aad_len, ciphertext, | |||||
buffer, size, control_tag, 0, &crid)) | |||||
goto out; | |||||
if (memcmp(cleartext, buffer, size) != 0) { | |||||
printf("%s (%zu) decryption mismatch:\n", alg->name, size); | |||||
printf("control:\n"); | |||||
hexdump(cleartext, size, NULL, 0); | |||||
printf("test (cryptodev device %s):\n", crfind(crid)); | |||||
hexdump(buffer, size, NULL, 0); | |||||
goto out; | |||||
} | |||||
if (verbose) | |||||
printf("%s (%zu) matched (cryptodev device %s)\n", | |||||
alg->name, size, crfind(crid)); | |||||
out: | |||||
free(aad); | |||||
free(ciphertext); | |||||
free(buffer); | |||||
free(cleartext); | |||||
free(iv); | |||||
free(key); | |||||
} | |||||
static void | |||||
run_test(struct alg *alg, size_t size) | run_test(struct alg *alg, size_t size) | ||||
{ | { | ||||
switch (alg->type) { | switch (alg->type) { | ||||
case T_HASH: | case T_HASH: | ||||
run_hash_test(alg, size); | run_hash_test(alg, size); | ||||
break; | break; | ||||
case T_HMAC: | case T_HMAC: | ||||
run_hmac_test(alg, size); | run_hmac_test(alg, size); | ||||
break; | break; | ||||
case T_BLKCIPHER: | case T_BLKCIPHER: | ||||
run_blkcipher_test(alg, size); | run_blkcipher_test(alg, size); | ||||
break; | break; | ||||
case T_AUTHENC: | case T_AUTHENC: | ||||
run_authenc_test(alg, size); | run_authenc_test(alg, size); | ||||
break; | break; | ||||
case T_GCM: | case T_GCM: | ||||
run_gcm_test(alg, size); | run_gcm_test(alg, size); | ||||
break; | break; | ||||
case T_CCM: | |||||
run_ccm_test(alg, size); | |||||
break; | |||||
} | } | ||||
} | } | ||||
static void | static void | ||||
run_test_sizes(struct alg *alg, size_t *sizes, u_int nsizes) | run_test_sizes(struct alg *alg, size_t *sizes, u_int nsizes) | ||||
{ | { | ||||
u_int i; | u_int i; | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
run_aead_tests(size_t *sizes, u_int nsizes) | run_aead_tests(size_t *sizes, u_int nsizes) | ||||
{ | { | ||||
u_int i; | u_int i; | ||||
for (i = 0; i < nitems(algs); i++) | for (i = 0; i < nitems(algs); i++) | ||||
if (algs[i].type == T_GCM) | if (algs[i].type == T_GCM || | ||||
algs[i].type == T_CCM) | |||||
run_test_sizes(&algs[i], sizes, nsizes); | run_test_sizes(&algs[i], sizes, nsizes); | ||||
} | } | ||||
int | int | ||||
main(int ac, char **av) | main(int ac, char **av) | ||||
{ | { | ||||
const char *algname; | const char *algname; | ||||
struct alg *alg; | struct alg *alg; | ||||
▲ Show 20 Lines • Show All 94 Lines • Show Last 20 Lines |