1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* 28*7c478bd9Sstevel@tonic-gate * Cleaned-up and optimized version of MD5, based on the reference 29*7c478bd9Sstevel@tonic-gate * implementation provided in RFC 1321. See RSA Copyright information 30*7c478bd9Sstevel@tonic-gate * below. 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * NOTE: All compiler data was gathered with SC4.2, and verified with SC5.x, 33*7c478bd9Sstevel@tonic-gate * as used to build Solaris 2.7. Hopefully the compiler behavior won't 34*7c478bd9Sstevel@tonic-gate * change for the worse in subsequent Solaris builds. 35*7c478bd9Sstevel@tonic-gate */ 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate /* 40*7c478bd9Sstevel@tonic-gate * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm 41*7c478bd9Sstevel@tonic-gate */ 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate /* 44*7c478bd9Sstevel@tonic-gate * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 45*7c478bd9Sstevel@tonic-gate * rights reserved. 46*7c478bd9Sstevel@tonic-gate * 47*7c478bd9Sstevel@tonic-gate * License to copy and use this software is granted provided that it 48*7c478bd9Sstevel@tonic-gate * is identified as the "RSA Data Security, Inc. MD5 Message-Digest 49*7c478bd9Sstevel@tonic-gate * Algorithm" in all material mentioning or referencing this software 50*7c478bd9Sstevel@tonic-gate * or this function. 51*7c478bd9Sstevel@tonic-gate * 52*7c478bd9Sstevel@tonic-gate * License is also granted to make and use derivative works provided 53*7c478bd9Sstevel@tonic-gate * that such works are identified as "derived from the RSA Data 54*7c478bd9Sstevel@tonic-gate * Security, Inc. MD5 Message-Digest Algorithm" in all material 55*7c478bd9Sstevel@tonic-gate * mentioning or referencing the derived work. 56*7c478bd9Sstevel@tonic-gate * 57*7c478bd9Sstevel@tonic-gate * RSA Data Security, Inc. makes no representations concerning either 58*7c478bd9Sstevel@tonic-gate * the merchantability of this software or the suitability of this 59*7c478bd9Sstevel@tonic-gate * software for any particular purpose. It is provided "as is" 60*7c478bd9Sstevel@tonic-gate * without express or implied warranty of any kind. 61*7c478bd9Sstevel@tonic-gate * 62*7c478bd9Sstevel@tonic-gate * These notices must be retained in any copies of any part of this 63*7c478bd9Sstevel@tonic-gate * documentation and/or software. 64*7c478bd9Sstevel@tonic-gate */ 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 67*7c478bd9Sstevel@tonic-gate #include <sys/md5.h> 68*7c478bd9Sstevel@tonic-gate #include <sys/md5_consts.h> /* MD5_CONST() optimization */ 69*7c478bd9Sstevel@tonic-gate #if !defined(_KERNEL) || defined(_BOOT) 70*7c478bd9Sstevel@tonic-gate #include <strings.h> 71*7c478bd9Sstevel@tonic-gate #endif /* !_KERNEL || _BOOT */ 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT) 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate /* 76*7c478bd9Sstevel@tonic-gate * In kernel module, the md5 module is created with two modlinkages: 77*7c478bd9Sstevel@tonic-gate * - a modlmisc that allows consumers to directly call the entry points 78*7c478bd9Sstevel@tonic-gate * MD5Init, MD5Update, and MD5Final. 79*7c478bd9Sstevel@tonic-gate * - a modlcrypto that allows the module to register with the Kernel 80*7c478bd9Sstevel@tonic-gate * Cryptographic Framework (KCF) as a software provider for the MD5 81*7c478bd9Sstevel@tonic-gate * mechanisms. 82*7c478bd9Sstevel@tonic-gate */ 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 85*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 86*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 87*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 88*7c478bd9Sstevel@tonic-gate #include <sys/crypto/common.h> 89*7c478bd9Sstevel@tonic-gate #include <sys/crypto/spi.h> 90*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 91*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 92*7c478bd9Sstevel@tonic-gate #include <sys/note.h> 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate extern struct mod_ops mod_miscops; 95*7c478bd9Sstevel@tonic-gate extern struct mod_ops mod_cryptoops; 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate /* 98*7c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 99*7c478bd9Sstevel@tonic-gate */ 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = { 102*7c478bd9Sstevel@tonic-gate &mod_miscops, 103*7c478bd9Sstevel@tonic-gate "MD5 Message-Digest Algorithm" 104*7c478bd9Sstevel@tonic-gate }; 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate static struct modlcrypto modlcrypto = { 107*7c478bd9Sstevel@tonic-gate &mod_cryptoops, 108*7c478bd9Sstevel@tonic-gate "MD5 Kernel SW Provider %I%" 109*7c478bd9Sstevel@tonic-gate }; 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 112*7c478bd9Sstevel@tonic-gate MODREV_1, 113*7c478bd9Sstevel@tonic-gate (void *)&modlmisc, 114*7c478bd9Sstevel@tonic-gate (void *)&modlcrypto, 115*7c478bd9Sstevel@tonic-gate NULL 116*7c478bd9Sstevel@tonic-gate }; 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate /* 119*7c478bd9Sstevel@tonic-gate * CSPI information (entry points, provider info, etc.) 120*7c478bd9Sstevel@tonic-gate */ 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate typedef enum md5_mech_type { 123*7c478bd9Sstevel@tonic-gate MD5_MECH_INFO_TYPE, /* SUN_CKM_MD5 */ 124*7c478bd9Sstevel@tonic-gate MD5_HMAC_MECH_INFO_TYPE, /* SUN_CKM_MD5_HMAC */ 125*7c478bd9Sstevel@tonic-gate MD5_HMAC_GEN_MECH_INFO_TYPE /* SUN_CKM_MD5_HMAC_GENERAL */ 126*7c478bd9Sstevel@tonic-gate } md5_mech_type_t; 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate #define MD5_DIGEST_LENGTH 16 /* MD5 digest length in bytes */ 129*7c478bd9Sstevel@tonic-gate #define MD5_HMAC_BLOCK_SIZE 64 /* MD5 block size */ 130*7c478bd9Sstevel@tonic-gate #define MD5_HMAC_MIN_KEY_LEN 8 /* MD5-HMAC min key length in bits */ 131*7c478bd9Sstevel@tonic-gate #define MD5_HMAC_MAX_KEY_LEN INT_MAX /* MD5-HMAC max key length in bits */ 132*7c478bd9Sstevel@tonic-gate #define MD5_HMAC_INTS_PER_BLOCK (MD5_HMAC_BLOCK_SIZE/sizeof (uint32_t)) 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate /* 135*7c478bd9Sstevel@tonic-gate * Context for MD5 mechanism. 136*7c478bd9Sstevel@tonic-gate */ 137*7c478bd9Sstevel@tonic-gate typedef struct md5_ctx { 138*7c478bd9Sstevel@tonic-gate md5_mech_type_t mc_mech_type; /* type of context */ 139*7c478bd9Sstevel@tonic-gate MD5_CTX mc_md5_ctx; /* MD5 context */ 140*7c478bd9Sstevel@tonic-gate } md5_ctx_t; 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate /* 143*7c478bd9Sstevel@tonic-gate * Context for MD5-HMAC and MD5-HMAC-GENERAL mechanisms. 144*7c478bd9Sstevel@tonic-gate */ 145*7c478bd9Sstevel@tonic-gate typedef struct md5_hmac_ctx { 146*7c478bd9Sstevel@tonic-gate md5_mech_type_t hc_mech_type; /* type of context */ 147*7c478bd9Sstevel@tonic-gate uint32_t hc_digest_len; /* digest len in bytes */ 148*7c478bd9Sstevel@tonic-gate MD5_CTX hc_icontext; /* inner MD5 context */ 149*7c478bd9Sstevel@tonic-gate MD5_CTX hc_ocontext; /* outer MD5 context */ 150*7c478bd9Sstevel@tonic-gate } md5_hmac_ctx_t; 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate /* 153*7c478bd9Sstevel@tonic-gate * Macros to access the MD5 or MD5-HMAC contexts from a context passed 154*7c478bd9Sstevel@tonic-gate * by KCF to one of the entry points. 155*7c478bd9Sstevel@tonic-gate */ 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate #define PROV_MD5_CTX(ctx) ((md5_ctx_t *)(ctx)->cc_provider_private) 158*7c478bd9Sstevel@tonic-gate #define PROV_MD5_HMAC_CTX(ctx) ((md5_hmac_ctx_t *)(ctx)->cc_provider_private) 159*7c478bd9Sstevel@tonic-gate /* to extract the digest length passed as mechanism parameter */ 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate #define PROV_MD5_GET_DIGEST_LEN(m, len) { \ 162*7c478bd9Sstevel@tonic-gate if (IS_P2ALIGNED((m)->cm_param, sizeof (ulong_t))) \ 163*7c478bd9Sstevel@tonic-gate (len) = (uint32_t)*((ulong_t *)mechanism->cm_param); \ 164*7c478bd9Sstevel@tonic-gate else { \ 165*7c478bd9Sstevel@tonic-gate ulong_t tmp_ulong; \ 166*7c478bd9Sstevel@tonic-gate bcopy((m)->cm_param, &tmp_ulong, sizeof (ulong_t)); \ 167*7c478bd9Sstevel@tonic-gate (len) = (uint32_t)tmp_ulong; \ 168*7c478bd9Sstevel@tonic-gate } \ 169*7c478bd9Sstevel@tonic-gate } 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate #define PROV_MD5_DIGEST_KEY(ctx, key, len, digest) { \ 172*7c478bd9Sstevel@tonic-gate MD5Init(ctx); \ 173*7c478bd9Sstevel@tonic-gate MD5Update(ctx, key, len); \ 174*7c478bd9Sstevel@tonic-gate MD5Final(digest, ctx); \ 175*7c478bd9Sstevel@tonic-gate } 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate /* 178*7c478bd9Sstevel@tonic-gate * Mechanism info structure passed to KCF during registration. 179*7c478bd9Sstevel@tonic-gate */ 180*7c478bd9Sstevel@tonic-gate static crypto_mech_info_t md5_mech_info_tab[] = { 181*7c478bd9Sstevel@tonic-gate /* MD5 */ 182*7c478bd9Sstevel@tonic-gate {SUN_CKM_MD5, MD5_MECH_INFO_TYPE, 183*7c478bd9Sstevel@tonic-gate CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC, 184*7c478bd9Sstevel@tonic-gate 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS}, 185*7c478bd9Sstevel@tonic-gate /* MD5-HMAC */ 186*7c478bd9Sstevel@tonic-gate {SUN_CKM_MD5_HMAC, MD5_HMAC_MECH_INFO_TYPE, 187*7c478bd9Sstevel@tonic-gate CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 188*7c478bd9Sstevel@tonic-gate MD5_HMAC_MIN_KEY_LEN, MD5_HMAC_MAX_KEY_LEN, 189*7c478bd9Sstevel@tonic-gate CRYPTO_KEYSIZE_UNIT_IN_BITS}, 190*7c478bd9Sstevel@tonic-gate /* MD5-HMAC GENERAL */ 191*7c478bd9Sstevel@tonic-gate {SUN_CKM_MD5_HMAC_GENERAL, MD5_HMAC_GEN_MECH_INFO_TYPE, 192*7c478bd9Sstevel@tonic-gate CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 193*7c478bd9Sstevel@tonic-gate MD5_HMAC_MIN_KEY_LEN, MD5_HMAC_MAX_KEY_LEN, 194*7c478bd9Sstevel@tonic-gate CRYPTO_KEYSIZE_UNIT_IN_BITS} 195*7c478bd9Sstevel@tonic-gate }; 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate static void md5_provider_status(crypto_provider_handle_t, uint_t *); 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate static crypto_control_ops_t md5_control_ops = { 200*7c478bd9Sstevel@tonic-gate md5_provider_status 201*7c478bd9Sstevel@tonic-gate }; 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate static int md5_digest_init(crypto_ctx_t *, crypto_mechanism_t *, 204*7c478bd9Sstevel@tonic-gate crypto_req_handle_t); 205*7c478bd9Sstevel@tonic-gate static int md5_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, 206*7c478bd9Sstevel@tonic-gate crypto_req_handle_t); 207*7c478bd9Sstevel@tonic-gate static int md5_digest_update(crypto_ctx_t *, crypto_data_t *, 208*7c478bd9Sstevel@tonic-gate crypto_req_handle_t); 209*7c478bd9Sstevel@tonic-gate static int md5_digest_final(crypto_ctx_t *, crypto_data_t *, 210*7c478bd9Sstevel@tonic-gate crypto_req_handle_t); 211*7c478bd9Sstevel@tonic-gate static int md5_digest_atomic(crypto_provider_handle_t, crypto_session_id_t, 212*7c478bd9Sstevel@tonic-gate crypto_mechanism_t *, crypto_data_t *, crypto_data_t *, 213*7c478bd9Sstevel@tonic-gate crypto_req_handle_t); 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate static crypto_digest_ops_t md5_digest_ops = { 216*7c478bd9Sstevel@tonic-gate md5_digest_init, 217*7c478bd9Sstevel@tonic-gate md5_digest, 218*7c478bd9Sstevel@tonic-gate md5_digest_update, 219*7c478bd9Sstevel@tonic-gate NULL, 220*7c478bd9Sstevel@tonic-gate md5_digest_final, 221*7c478bd9Sstevel@tonic-gate md5_digest_atomic 222*7c478bd9Sstevel@tonic-gate }; 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate static int md5_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *, 225*7c478bd9Sstevel@tonic-gate crypto_spi_ctx_template_t, crypto_req_handle_t); 226*7c478bd9Sstevel@tonic-gate static int md5_mac_update(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t); 227*7c478bd9Sstevel@tonic-gate static int md5_mac_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t); 228*7c478bd9Sstevel@tonic-gate static int md5_mac_atomic(crypto_provider_handle_t, crypto_session_id_t, 229*7c478bd9Sstevel@tonic-gate crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *, 230*7c478bd9Sstevel@tonic-gate crypto_spi_ctx_template_t, crypto_req_handle_t); 231*7c478bd9Sstevel@tonic-gate static int md5_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t, 232*7c478bd9Sstevel@tonic-gate crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *, 233*7c478bd9Sstevel@tonic-gate crypto_spi_ctx_template_t, crypto_req_handle_t); 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate static crypto_mac_ops_t md5_mac_ops = { 236*7c478bd9Sstevel@tonic-gate md5_mac_init, 237*7c478bd9Sstevel@tonic-gate NULL, 238*7c478bd9Sstevel@tonic-gate md5_mac_update, 239*7c478bd9Sstevel@tonic-gate md5_mac_final, 240*7c478bd9Sstevel@tonic-gate md5_mac_atomic, 241*7c478bd9Sstevel@tonic-gate md5_mac_verify_atomic 242*7c478bd9Sstevel@tonic-gate }; 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate static int md5_create_ctx_template(crypto_provider_handle_t, 245*7c478bd9Sstevel@tonic-gate crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *, 246*7c478bd9Sstevel@tonic-gate size_t *, crypto_req_handle_t); 247*7c478bd9Sstevel@tonic-gate static int md5_free_context(crypto_ctx_t *); 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate static crypto_ctx_ops_t md5_ctx_ops = { 250*7c478bd9Sstevel@tonic-gate md5_create_ctx_template, 251*7c478bd9Sstevel@tonic-gate md5_free_context 252*7c478bd9Sstevel@tonic-gate }; 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate static crypto_ops_t md5_crypto_ops = { 255*7c478bd9Sstevel@tonic-gate &md5_control_ops, 256*7c478bd9Sstevel@tonic-gate &md5_digest_ops, 257*7c478bd9Sstevel@tonic-gate NULL, 258*7c478bd9Sstevel@tonic-gate &md5_mac_ops, 259*7c478bd9Sstevel@tonic-gate NULL, 260*7c478bd9Sstevel@tonic-gate NULL, 261*7c478bd9Sstevel@tonic-gate NULL, 262*7c478bd9Sstevel@tonic-gate NULL, 263*7c478bd9Sstevel@tonic-gate NULL, 264*7c478bd9Sstevel@tonic-gate NULL, 265*7c478bd9Sstevel@tonic-gate NULL, 266*7c478bd9Sstevel@tonic-gate NULL, 267*7c478bd9Sstevel@tonic-gate NULL, 268*7c478bd9Sstevel@tonic-gate &md5_ctx_ops 269*7c478bd9Sstevel@tonic-gate }; 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate static crypto_provider_info_t md5_prov_info = { 272*7c478bd9Sstevel@tonic-gate CRYPTO_SPI_VERSION_1, 273*7c478bd9Sstevel@tonic-gate "MD5 Software Provider", 274*7c478bd9Sstevel@tonic-gate CRYPTO_SW_PROVIDER, 275*7c478bd9Sstevel@tonic-gate {&modlinkage}, 276*7c478bd9Sstevel@tonic-gate NULL, 277*7c478bd9Sstevel@tonic-gate &md5_crypto_ops, 278*7c478bd9Sstevel@tonic-gate sizeof (md5_mech_info_tab)/sizeof (crypto_mech_info_t), 279*7c478bd9Sstevel@tonic-gate md5_mech_info_tab 280*7c478bd9Sstevel@tonic-gate }; 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate static crypto_kcf_provider_handle_t md5_prov_handle = NULL; 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate int 285*7c478bd9Sstevel@tonic-gate _init(void) 286*7c478bd9Sstevel@tonic-gate { 287*7c478bd9Sstevel@tonic-gate int ret; 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate if ((ret = mod_install(&modlinkage)) != 0) 290*7c478bd9Sstevel@tonic-gate return (ret); 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate /* 293*7c478bd9Sstevel@tonic-gate * Register with KCF. If the registration fails, log an 294*7c478bd9Sstevel@tonic-gate * error but do not uninstall the module, since the functionality 295*7c478bd9Sstevel@tonic-gate * provided by misc/md5 should still be available. 296*7c478bd9Sstevel@tonic-gate */ 297*7c478bd9Sstevel@tonic-gate if ((ret = crypto_register_provider(&md5_prov_info, 298*7c478bd9Sstevel@tonic-gate &md5_prov_handle)) != CRYPTO_SUCCESS) 299*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "md5 _init: " 300*7c478bd9Sstevel@tonic-gate "crypto_register_provider() failed (0x%x)", ret); 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate return (0); 303*7c478bd9Sstevel@tonic-gate } 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate int 306*7c478bd9Sstevel@tonic-gate _fini(void) 307*7c478bd9Sstevel@tonic-gate { 308*7c478bd9Sstevel@tonic-gate int ret; 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate /* 311*7c478bd9Sstevel@tonic-gate * Unregister from KCF if previous registration succeeded. 312*7c478bd9Sstevel@tonic-gate */ 313*7c478bd9Sstevel@tonic-gate if (md5_prov_handle != NULL) { 314*7c478bd9Sstevel@tonic-gate if ((ret = crypto_unregister_provider(md5_prov_handle)) != 315*7c478bd9Sstevel@tonic-gate CRYPTO_SUCCESS) { 316*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "md5 _fini: " 317*7c478bd9Sstevel@tonic-gate "crypto_unregister_provider() failed (0x%x)", ret); 318*7c478bd9Sstevel@tonic-gate return (EBUSY); 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate md5_prov_handle = NULL; 321*7c478bd9Sstevel@tonic-gate } 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 324*7c478bd9Sstevel@tonic-gate } 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate int 327*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 328*7c478bd9Sstevel@tonic-gate { 329*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL && !_BOOT */ 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate static void Encode(uint8_t *, uint32_t *, size_t); 334*7c478bd9Sstevel@tonic-gate static void MD5Transform(uint32_t, uint32_t, uint32_t, uint32_t, MD5_CTX *, 335*7c478bd9Sstevel@tonic-gate const uint8_t [64]); 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate static uint8_t PADDING[64] = { 0x80, /* all zeros */ }; 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate /* 340*7c478bd9Sstevel@tonic-gate * F, G, H and I are the basic MD5 functions. 341*7c478bd9Sstevel@tonic-gate */ 342*7c478bd9Sstevel@tonic-gate #define F(b, c, d) (((b) & (c)) | ((~b) & (d))) 343*7c478bd9Sstevel@tonic-gate #define G(b, c, d) (((b) & (d)) | ((c) & (~d))) 344*7c478bd9Sstevel@tonic-gate #define H(b, c, d) ((b) ^ (c) ^ (d)) 345*7c478bd9Sstevel@tonic-gate #define I(b, c, d) ((c) ^ ((b) | (~d))) 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate /* 348*7c478bd9Sstevel@tonic-gate * ROTATE_LEFT rotates x left n bits. 349*7c478bd9Sstevel@tonic-gate */ 350*7c478bd9Sstevel@tonic-gate #define ROTATE_LEFT(x, n) \ 351*7c478bd9Sstevel@tonic-gate (((x) << (n)) | ((x) >> ((sizeof (x) << 3) - (n)))) 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate /* 354*7c478bd9Sstevel@tonic-gate * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. 355*7c478bd9Sstevel@tonic-gate * Rotation is separate from addition to prevent recomputation. 356*7c478bd9Sstevel@tonic-gate */ 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate #define FF(a, b, c, d, x, s, ac) { \ 359*7c478bd9Sstevel@tonic-gate (a) += F((b), (c), (d)) + (x) + (uint32_t)(ac); \ 360*7c478bd9Sstevel@tonic-gate (a) = ROTATE_LEFT((a), (s)); \ 361*7c478bd9Sstevel@tonic-gate (a) += (b); \ 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate #define GG(a, b, c, d, x, s, ac) { \ 365*7c478bd9Sstevel@tonic-gate (a) += G((b), (c), (d)) + (x) + (uint32_t)(ac); \ 366*7c478bd9Sstevel@tonic-gate (a) = ROTATE_LEFT((a), (s)); \ 367*7c478bd9Sstevel@tonic-gate (a) += (b); \ 368*7c478bd9Sstevel@tonic-gate } 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate #define HH(a, b, c, d, x, s, ac) { \ 371*7c478bd9Sstevel@tonic-gate (a) += H((b), (c), (d)) + (x) + (uint32_t)(ac); \ 372*7c478bd9Sstevel@tonic-gate (a) = ROTATE_LEFT((a), (s)); \ 373*7c478bd9Sstevel@tonic-gate (a) += (b); \ 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate #define II(a, b, c, d, x, s, ac) { \ 377*7c478bd9Sstevel@tonic-gate (a) += I((b), (c), (d)) + (x) + (uint32_t)(ac); \ 378*7c478bd9Sstevel@tonic-gate (a) = ROTATE_LEFT((a), (s)); \ 379*7c478bd9Sstevel@tonic-gate (a) += (b); \ 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate /* 383*7c478bd9Sstevel@tonic-gate * Loading 32-bit constants on a RISC is expensive since it involves both a 384*7c478bd9Sstevel@tonic-gate * `sethi' and an `or'. thus, we instead have the compiler generate `ld's to 385*7c478bd9Sstevel@tonic-gate * load the constants from an array called `md5_consts'. however, on intel 386*7c478bd9Sstevel@tonic-gate * (and other CISC processors), it is cheaper to load the constant 387*7c478bd9Sstevel@tonic-gate * directly. thus, the c code in MD5Transform() uses the macro MD5_CONST() 388*7c478bd9Sstevel@tonic-gate * which either expands to a constant or an array reference, depending on the 389*7c478bd9Sstevel@tonic-gate * architecture the code is being compiled for. 390*7c478bd9Sstevel@tonic-gate * 391*7c478bd9Sstevel@tonic-gate * Right now, i386 and amd64 are the CISC exceptions. 392*7c478bd9Sstevel@tonic-gate * If we get another CISC ISA, we'll have to change the ifdef. 393*7c478bd9Sstevel@tonic-gate */ 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate #define MD5_CONST(x) (MD5_CONST_ ## x) 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate #else 400*7c478bd9Sstevel@tonic-gate /* 401*7c478bd9Sstevel@tonic-gate * sparc/RISC optimization: 402*7c478bd9Sstevel@tonic-gate * 403*7c478bd9Sstevel@tonic-gate * while it is somewhat counter-intuitive, on sparc (and presumably other RISC 404*7c478bd9Sstevel@tonic-gate * machines), it is more efficient to place all the constants used in this 405*7c478bd9Sstevel@tonic-gate * function in an array and load the values out of the array than to manually 406*7c478bd9Sstevel@tonic-gate * load the constants. this is because setting a register to a 32-bit value 407*7c478bd9Sstevel@tonic-gate * takes two ops in most cases: a `sethi' and an `or', but loading a 32-bit 408*7c478bd9Sstevel@tonic-gate * value from memory only takes one `ld' (or `lduw' on v9). while this 409*7c478bd9Sstevel@tonic-gate * increases memory usage, the compiler can find enough other things to do 410*7c478bd9Sstevel@tonic-gate * while waiting to keep the pipeline does not stall. additionally, it is 411*7c478bd9Sstevel@tonic-gate * likely that many of these constants are cached so that later accesses do 412*7c478bd9Sstevel@tonic-gate * not even go out to the bus. 413*7c478bd9Sstevel@tonic-gate * 414*7c478bd9Sstevel@tonic-gate * this array is declared `static' to keep the compiler from having to 415*7c478bd9Sstevel@tonic-gate * bcopy() this array onto the stack frame of MD5Transform() each time it is 416*7c478bd9Sstevel@tonic-gate * called -- which is unacceptably expensive. 417*7c478bd9Sstevel@tonic-gate * 418*7c478bd9Sstevel@tonic-gate * the `const' is to ensure that callers are good citizens and do not try to 419*7c478bd9Sstevel@tonic-gate * munge the array. since these routines are going to be called from inside 420*7c478bd9Sstevel@tonic-gate * multithreaded kernelland, this is a good safety check. -- `constants' will 421*7c478bd9Sstevel@tonic-gate * end up in .rodata. 422*7c478bd9Sstevel@tonic-gate * 423*7c478bd9Sstevel@tonic-gate * unfortunately, loading from an array in this manner hurts performance under 424*7c478bd9Sstevel@tonic-gate * intel (and presumably other CISC machines). so, there is a macro, 425*7c478bd9Sstevel@tonic-gate * MD5_CONST(), used in MD5Transform(), that either expands to a reference to 426*7c478bd9Sstevel@tonic-gate * this array, or to the actual constant, depending on what platform this code 427*7c478bd9Sstevel@tonic-gate * is compiled for. 428*7c478bd9Sstevel@tonic-gate */ 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate static const uint32_t md5_consts[] = { 431*7c478bd9Sstevel@tonic-gate MD5_CONST_0, MD5_CONST_1, MD5_CONST_2, MD5_CONST_3, 432*7c478bd9Sstevel@tonic-gate MD5_CONST_4, MD5_CONST_5, MD5_CONST_6, MD5_CONST_7, 433*7c478bd9Sstevel@tonic-gate MD5_CONST_8, MD5_CONST_9, MD5_CONST_10, MD5_CONST_11, 434*7c478bd9Sstevel@tonic-gate MD5_CONST_12, MD5_CONST_13, MD5_CONST_14, MD5_CONST_15, 435*7c478bd9Sstevel@tonic-gate MD5_CONST_16, MD5_CONST_17, MD5_CONST_18, MD5_CONST_19, 436*7c478bd9Sstevel@tonic-gate MD5_CONST_20, MD5_CONST_21, MD5_CONST_22, MD5_CONST_23, 437*7c478bd9Sstevel@tonic-gate MD5_CONST_24, MD5_CONST_25, MD5_CONST_26, MD5_CONST_27, 438*7c478bd9Sstevel@tonic-gate MD5_CONST_28, MD5_CONST_29, MD5_CONST_30, MD5_CONST_31, 439*7c478bd9Sstevel@tonic-gate MD5_CONST_32, MD5_CONST_33, MD5_CONST_34, MD5_CONST_35, 440*7c478bd9Sstevel@tonic-gate MD5_CONST_36, MD5_CONST_37, MD5_CONST_38, MD5_CONST_39, 441*7c478bd9Sstevel@tonic-gate MD5_CONST_40, MD5_CONST_41, MD5_CONST_42, MD5_CONST_43, 442*7c478bd9Sstevel@tonic-gate MD5_CONST_44, MD5_CONST_45, MD5_CONST_46, MD5_CONST_47, 443*7c478bd9Sstevel@tonic-gate MD5_CONST_48, MD5_CONST_49, MD5_CONST_50, MD5_CONST_51, 444*7c478bd9Sstevel@tonic-gate MD5_CONST_52, MD5_CONST_53, MD5_CONST_54, MD5_CONST_55, 445*7c478bd9Sstevel@tonic-gate MD5_CONST_56, MD5_CONST_57, MD5_CONST_58, MD5_CONST_59, 446*7c478bd9Sstevel@tonic-gate MD5_CONST_60, MD5_CONST_61, MD5_CONST_62, MD5_CONST_63 447*7c478bd9Sstevel@tonic-gate }; 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate #define MD5_CONST(x) (md5_consts[x]) 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate #endif 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate /* 454*7c478bd9Sstevel@tonic-gate * MD5Init() 455*7c478bd9Sstevel@tonic-gate * 456*7c478bd9Sstevel@tonic-gate * purpose: initializes the md5 context and begins and md5 digest operation 457*7c478bd9Sstevel@tonic-gate * input: MD5_CTX * : the context to initialize. 458*7c478bd9Sstevel@tonic-gate * output: void 459*7c478bd9Sstevel@tonic-gate */ 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate void 462*7c478bd9Sstevel@tonic-gate MD5Init(MD5_CTX *ctx) 463*7c478bd9Sstevel@tonic-gate { 464*7c478bd9Sstevel@tonic-gate ctx->count[0] = ctx->count[1] = 0; 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate /* load magic initialization constants */ 467*7c478bd9Sstevel@tonic-gate ctx->state[0] = MD5_INIT_CONST_1; 468*7c478bd9Sstevel@tonic-gate ctx->state[1] = MD5_INIT_CONST_2; 469*7c478bd9Sstevel@tonic-gate ctx->state[2] = MD5_INIT_CONST_3; 470*7c478bd9Sstevel@tonic-gate ctx->state[3] = MD5_INIT_CONST_4; 471*7c478bd9Sstevel@tonic-gate } 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate /* 474*7c478bd9Sstevel@tonic-gate * MD5Update() 475*7c478bd9Sstevel@tonic-gate * 476*7c478bd9Sstevel@tonic-gate * purpose: continues an md5 digest operation, using the message block 477*7c478bd9Sstevel@tonic-gate * to update the context. 478*7c478bd9Sstevel@tonic-gate * input: MD5_CTX * : the context to update 479*7c478bd9Sstevel@tonic-gate * uint8_t * : the message block 480*7c478bd9Sstevel@tonic-gate * uint32_t : the length of the message block in bytes 481*7c478bd9Sstevel@tonic-gate * output: void 482*7c478bd9Sstevel@tonic-gate * 483*7c478bd9Sstevel@tonic-gate * MD5 crunches in 64-byte blocks. All numeric constants here are related to 484*7c478bd9Sstevel@tonic-gate * that property of MD5. 485*7c478bd9Sstevel@tonic-gate */ 486*7c478bd9Sstevel@tonic-gate 487*7c478bd9Sstevel@tonic-gate void 488*7c478bd9Sstevel@tonic-gate MD5Update(MD5_CTX *ctx, const void *inpp, unsigned int input_len) 489*7c478bd9Sstevel@tonic-gate { 490*7c478bd9Sstevel@tonic-gate uint32_t i, buf_index, buf_len; 491*7c478bd9Sstevel@tonic-gate const unsigned char *input = (const unsigned char *)inpp; 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate /* compute (number of bytes computed so far) mod 64 */ 494*7c478bd9Sstevel@tonic-gate buf_index = (ctx->count[0] >> 3) & 0x3F; 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate /* update number of bits hashed into this MD5 computation so far */ 497*7c478bd9Sstevel@tonic-gate if ((ctx->count[0] += (input_len << 3)) < (input_len << 3)) 498*7c478bd9Sstevel@tonic-gate ctx->count[1]++; 499*7c478bd9Sstevel@tonic-gate ctx->count[1] += (input_len >> 29); 500*7c478bd9Sstevel@tonic-gate 501*7c478bd9Sstevel@tonic-gate buf_len = 64 - buf_index; 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate /* transform as many times as possible */ 504*7c478bd9Sstevel@tonic-gate i = 0; 505*7c478bd9Sstevel@tonic-gate if (input_len >= buf_len) { 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate /* 508*7c478bd9Sstevel@tonic-gate * general optimization: 509*7c478bd9Sstevel@tonic-gate * 510*7c478bd9Sstevel@tonic-gate * only do initial bcopy() and MD5Transform() if 511*7c478bd9Sstevel@tonic-gate * buf_index != 0. if buf_index == 0, we're just 512*7c478bd9Sstevel@tonic-gate * wasting our time doing the bcopy() since there 513*7c478bd9Sstevel@tonic-gate * wasn't any data left over from a previous call to 514*7c478bd9Sstevel@tonic-gate * MD5Update(). 515*7c478bd9Sstevel@tonic-gate */ 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate if (buf_index) { 518*7c478bd9Sstevel@tonic-gate bcopy(input, &ctx->buf_un.buf8[buf_index], buf_len); 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate MD5Transform(ctx->state[0], ctx->state[1], 521*7c478bd9Sstevel@tonic-gate ctx->state[2], ctx->state[3], ctx, 522*7c478bd9Sstevel@tonic-gate ctx->buf_un.buf8); 523*7c478bd9Sstevel@tonic-gate 524*7c478bd9Sstevel@tonic-gate i = buf_len; 525*7c478bd9Sstevel@tonic-gate } 526*7c478bd9Sstevel@tonic-gate 527*7c478bd9Sstevel@tonic-gate for (; i + 63 < input_len; i += 64) 528*7c478bd9Sstevel@tonic-gate MD5Transform(ctx->state[0], ctx->state[1], 529*7c478bd9Sstevel@tonic-gate ctx->state[2], ctx->state[3], ctx, &input[i]); 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate /* 532*7c478bd9Sstevel@tonic-gate * general optimization: 533*7c478bd9Sstevel@tonic-gate * 534*7c478bd9Sstevel@tonic-gate * if i and input_len are the same, return now instead 535*7c478bd9Sstevel@tonic-gate * of calling bcopy(), since the bcopy() in this 536*7c478bd9Sstevel@tonic-gate * case will be an expensive nop. 537*7c478bd9Sstevel@tonic-gate */ 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate if (input_len == i) 540*7c478bd9Sstevel@tonic-gate return; 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate buf_index = 0; 543*7c478bd9Sstevel@tonic-gate } 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate /* buffer remaining input */ 546*7c478bd9Sstevel@tonic-gate bcopy(&input[i], &ctx->buf_un.buf8[buf_index], input_len - i); 547*7c478bd9Sstevel@tonic-gate } 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate /* 550*7c478bd9Sstevel@tonic-gate * MD5Final() 551*7c478bd9Sstevel@tonic-gate * 552*7c478bd9Sstevel@tonic-gate * purpose: ends an md5 digest operation, finalizing the message digest and 553*7c478bd9Sstevel@tonic-gate * zeroing the context. 554*7c478bd9Sstevel@tonic-gate * input: uint8_t * : a buffer to store the digest in 555*7c478bd9Sstevel@tonic-gate * MD5_CTX * : the context to finalize, save, and zero 556*7c478bd9Sstevel@tonic-gate * output: void 557*7c478bd9Sstevel@tonic-gate */ 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate void 560*7c478bd9Sstevel@tonic-gate MD5Final(unsigned char *digest, MD5_CTX *ctx) 561*7c478bd9Sstevel@tonic-gate { 562*7c478bd9Sstevel@tonic-gate uint8_t bitcount_le[sizeof (ctx->count)]; 563*7c478bd9Sstevel@tonic-gate uint32_t index = (ctx->count[0] >> 3) & 0x3f; 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate /* store bit count, little endian */ 566*7c478bd9Sstevel@tonic-gate Encode(bitcount_le, ctx->count, sizeof (bitcount_le)); 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate /* pad out to 56 mod 64 */ 569*7c478bd9Sstevel@tonic-gate MD5Update(ctx, PADDING, ((index < 56) ? 56 : 120) - index); 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate /* append length (before padding) */ 572*7c478bd9Sstevel@tonic-gate MD5Update(ctx, bitcount_le, sizeof (bitcount_le)); 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate /* store state in digest */ 575*7c478bd9Sstevel@tonic-gate Encode(digest, ctx->state, sizeof (ctx->state)); 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate #ifndef _KERNEL 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate void 581*7c478bd9Sstevel@tonic-gate md5_calc(unsigned char *output, unsigned char *input, unsigned int inlen) 582*7c478bd9Sstevel@tonic-gate { 583*7c478bd9Sstevel@tonic-gate MD5_CTX context; 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate MD5Init(&context); 586*7c478bd9Sstevel@tonic-gate MD5Update(&context, input, inlen); 587*7c478bd9Sstevel@tonic-gate MD5Final(output, &context); 588*7c478bd9Sstevel@tonic-gate } 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate #endif /* !_KERNEL */ 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate /* 593*7c478bd9Sstevel@tonic-gate * Little-endian optimization: I don't need to do any weirdness. On 594*7c478bd9Sstevel@tonic-gate * some little-endian boxen, I'll have to do alignment checks, but I can do 595*7c478bd9Sstevel@tonic-gate * that below. 596*7c478bd9Sstevel@tonic-gate */ 597*7c478bd9Sstevel@tonic-gate 598*7c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate #if !defined(__i386) && !defined(__amd64) 601*7c478bd9Sstevel@tonic-gate /* 602*7c478bd9Sstevel@tonic-gate * i386 and amd64 don't require aligned 4-byte loads. The symbol 603*7c478bd9Sstevel@tonic-gate * _MD5_CHECK_ALIGNMENT indicates below whether the MD5Transform function 604*7c478bd9Sstevel@tonic-gate * requires alignment checking. 605*7c478bd9Sstevel@tonic-gate */ 606*7c478bd9Sstevel@tonic-gate #define _MD5_CHECK_ALIGNMENT 607*7c478bd9Sstevel@tonic-gate #endif /* !__i386 && !__amd64 */ 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate #define LOAD_LITTLE_32(addr) (*(uint32_t *)(addr)) 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate /* 612*7c478bd9Sstevel@tonic-gate * sparc v9/v8plus optimization: 613*7c478bd9Sstevel@tonic-gate * 614*7c478bd9Sstevel@tonic-gate * on the sparc v9/v8plus, we can load data little endian. however, since 615*7c478bd9Sstevel@tonic-gate * the compiler doesn't have direct support for little endian, we 616*7c478bd9Sstevel@tonic-gate * link to an assembly-language routine `load_little_32' to do 617*7c478bd9Sstevel@tonic-gate * the magic. note that special care must be taken to ensure the 618*7c478bd9Sstevel@tonic-gate * address is 32-bit aligned -- in the interest of speed, we don't 619*7c478bd9Sstevel@tonic-gate * check to make sure, since careful programming can guarantee this 620*7c478bd9Sstevel@tonic-gate * for us. 621*7c478bd9Sstevel@tonic-gate */ 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate #elif defined(sun4u) 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate /* Define alignment check because we can 4-byte load as little endian. */ 626*7c478bd9Sstevel@tonic-gate #define _MD5_CHECK_ALIGNMENT 627*7c478bd9Sstevel@tonic-gate extern uint32_t load_little_32(uint32_t *); 628*7c478bd9Sstevel@tonic-gate #define LOAD_LITTLE_32(addr) load_little_32((uint32_t *)(addr)) 629*7c478bd9Sstevel@tonic-gate 630*7c478bd9Sstevel@tonic-gate /* Placate lint */ 631*7c478bd9Sstevel@tonic-gate #if defined(__lint) 632*7c478bd9Sstevel@tonic-gate uint32_t 633*7c478bd9Sstevel@tonic-gate load_little_32(uint32_t *addr) 634*7c478bd9Sstevel@tonic-gate { 635*7c478bd9Sstevel@tonic-gate return (*addr); 636*7c478bd9Sstevel@tonic-gate } 637*7c478bd9Sstevel@tonic-gate #endif 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate #else /* big endian -- will work on little endian, but slowly */ 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate /* Since we do byte operations, we don't have to check for alignment. */ 642*7c478bd9Sstevel@tonic-gate #define LOAD_LITTLE_32(addr) \ 643*7c478bd9Sstevel@tonic-gate ((addr)[0] | ((addr)[1] << 8) | ((addr)[2] << 16) | ((addr)[3] << 24)) 644*7c478bd9Sstevel@tonic-gate #endif 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate /* 647*7c478bd9Sstevel@tonic-gate * sparc register window optimization: 648*7c478bd9Sstevel@tonic-gate * 649*7c478bd9Sstevel@tonic-gate * `a', `b', `c', and `d' are passed into MD5Transform explicitly 650*7c478bd9Sstevel@tonic-gate * since it increases the number of registers available to the 651*7c478bd9Sstevel@tonic-gate * compiler. under this scheme, these variables can be held in 652*7c478bd9Sstevel@tonic-gate * %i0 - %i3, which leaves more local and out registers available. 653*7c478bd9Sstevel@tonic-gate */ 654*7c478bd9Sstevel@tonic-gate 655*7c478bd9Sstevel@tonic-gate /* 656*7c478bd9Sstevel@tonic-gate * MD5Transform() 657*7c478bd9Sstevel@tonic-gate * 658*7c478bd9Sstevel@tonic-gate * purpose: md5 transformation -- updates the digest based on `block' 659*7c478bd9Sstevel@tonic-gate * input: uint32_t : bytes 1 - 4 of the digest 660*7c478bd9Sstevel@tonic-gate * uint32_t : bytes 5 - 8 of the digest 661*7c478bd9Sstevel@tonic-gate * uint32_t : bytes 9 - 12 of the digest 662*7c478bd9Sstevel@tonic-gate * uint32_t : bytes 12 - 16 of the digest 663*7c478bd9Sstevel@tonic-gate * MD5_CTX * : the context to update 664*7c478bd9Sstevel@tonic-gate * uint8_t [64]: the block to use to update the digest 665*7c478bd9Sstevel@tonic-gate * output: void 666*7c478bd9Sstevel@tonic-gate */ 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate static void 669*7c478bd9Sstevel@tonic-gate MD5Transform(uint32_t a, uint32_t b, uint32_t c, uint32_t d, 670*7c478bd9Sstevel@tonic-gate MD5_CTX *ctx, const uint8_t block[64]) 671*7c478bd9Sstevel@tonic-gate { 672*7c478bd9Sstevel@tonic-gate /* 673*7c478bd9Sstevel@tonic-gate * general optimization: 674*7c478bd9Sstevel@tonic-gate * 675*7c478bd9Sstevel@tonic-gate * use individual integers instead of using an array. this is a 676*7c478bd9Sstevel@tonic-gate * win, although the amount it wins by seems to vary quite a bit. 677*7c478bd9Sstevel@tonic-gate */ 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate register uint32_t x_0, x_1, x_2, x_3, x_4, x_5, x_6, x_7; 680*7c478bd9Sstevel@tonic-gate register uint32_t x_8, x_9, x_10, x_11, x_12, x_13, x_14, x_15; 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate /* 683*7c478bd9Sstevel@tonic-gate * general optimization: 684*7c478bd9Sstevel@tonic-gate * 685*7c478bd9Sstevel@tonic-gate * the compiler (at least SC4.2/5.x) generates better code if 686*7c478bd9Sstevel@tonic-gate * variable use is localized. in this case, swapping the integers in 687*7c478bd9Sstevel@tonic-gate * this order allows `x_0 'to be swapped nearest to its first use in 688*7c478bd9Sstevel@tonic-gate * FF(), and likewise for `x_1' and up. note that the compiler 689*7c478bd9Sstevel@tonic-gate * prefers this to doing each swap right before the FF() that 690*7c478bd9Sstevel@tonic-gate * uses it. 691*7c478bd9Sstevel@tonic-gate */ 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate /* 694*7c478bd9Sstevel@tonic-gate * sparc v9/v8plus optimization: 695*7c478bd9Sstevel@tonic-gate * 696*7c478bd9Sstevel@tonic-gate * if `block' is already aligned on a 4-byte boundary, use the 697*7c478bd9Sstevel@tonic-gate * optimized load_little_32() directly. otherwise, bcopy() 698*7c478bd9Sstevel@tonic-gate * into a buffer that *is* aligned on a 4-byte boundary and 699*7c478bd9Sstevel@tonic-gate * then do the load_little_32() on that buffer. benchmarks 700*7c478bd9Sstevel@tonic-gate * have shown that using the bcopy() is better than loading 701*7c478bd9Sstevel@tonic-gate * the bytes individually and doing the endian-swap by hand. 702*7c478bd9Sstevel@tonic-gate * 703*7c478bd9Sstevel@tonic-gate * even though it's quite tempting to assign to do: 704*7c478bd9Sstevel@tonic-gate * 705*7c478bd9Sstevel@tonic-gate * blk = bcopy(blk, ctx->buf_un.buf32, sizeof (ctx->buf_un.buf32)); 706*7c478bd9Sstevel@tonic-gate * 707*7c478bd9Sstevel@tonic-gate * and only have one set of LOAD_LITTLE_32()'s, the compiler (at least 708*7c478bd9Sstevel@tonic-gate * SC4.2/5.x) *does not* like that, so please resist the urge. 709*7c478bd9Sstevel@tonic-gate */ 710*7c478bd9Sstevel@tonic-gate 711*7c478bd9Sstevel@tonic-gate #ifdef _MD5_CHECK_ALIGNMENT 712*7c478bd9Sstevel@tonic-gate if ((uintptr_t)block & 0x3) { /* not 4-byte aligned? */ 713*7c478bd9Sstevel@tonic-gate bcopy(block, ctx->buf_un.buf32, sizeof (ctx->buf_un.buf32)); 714*7c478bd9Sstevel@tonic-gate x_15 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 15); 715*7c478bd9Sstevel@tonic-gate x_14 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 14); 716*7c478bd9Sstevel@tonic-gate x_13 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 13); 717*7c478bd9Sstevel@tonic-gate x_12 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 12); 718*7c478bd9Sstevel@tonic-gate x_11 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 11); 719*7c478bd9Sstevel@tonic-gate x_10 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 10); 720*7c478bd9Sstevel@tonic-gate x_9 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 9); 721*7c478bd9Sstevel@tonic-gate x_8 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 8); 722*7c478bd9Sstevel@tonic-gate x_7 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 7); 723*7c478bd9Sstevel@tonic-gate x_6 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 6); 724*7c478bd9Sstevel@tonic-gate x_5 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 5); 725*7c478bd9Sstevel@tonic-gate x_4 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 4); 726*7c478bd9Sstevel@tonic-gate x_3 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 3); 727*7c478bd9Sstevel@tonic-gate x_2 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 2); 728*7c478bd9Sstevel@tonic-gate x_1 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 1); 729*7c478bd9Sstevel@tonic-gate x_0 = LOAD_LITTLE_32(ctx->buf_un.buf32 + 0); 730*7c478bd9Sstevel@tonic-gate } else 731*7c478bd9Sstevel@tonic-gate #endif 732*7c478bd9Sstevel@tonic-gate { 733*7c478bd9Sstevel@tonic-gate x_15 = LOAD_LITTLE_32(block + 60); 734*7c478bd9Sstevel@tonic-gate x_14 = LOAD_LITTLE_32(block + 56); 735*7c478bd9Sstevel@tonic-gate x_13 = LOAD_LITTLE_32(block + 52); 736*7c478bd9Sstevel@tonic-gate x_12 = LOAD_LITTLE_32(block + 48); 737*7c478bd9Sstevel@tonic-gate x_11 = LOAD_LITTLE_32(block + 44); 738*7c478bd9Sstevel@tonic-gate x_10 = LOAD_LITTLE_32(block + 40); 739*7c478bd9Sstevel@tonic-gate x_9 = LOAD_LITTLE_32(block + 36); 740*7c478bd9Sstevel@tonic-gate x_8 = LOAD_LITTLE_32(block + 32); 741*7c478bd9Sstevel@tonic-gate x_7 = LOAD_LITTLE_32(block + 28); 742*7c478bd9Sstevel@tonic-gate x_6 = LOAD_LITTLE_32(block + 24); 743*7c478bd9Sstevel@tonic-gate x_5 = LOAD_LITTLE_32(block + 20); 744*7c478bd9Sstevel@tonic-gate x_4 = LOAD_LITTLE_32(block + 16); 745*7c478bd9Sstevel@tonic-gate x_3 = LOAD_LITTLE_32(block + 12); 746*7c478bd9Sstevel@tonic-gate x_2 = LOAD_LITTLE_32(block + 8); 747*7c478bd9Sstevel@tonic-gate x_1 = LOAD_LITTLE_32(block + 4); 748*7c478bd9Sstevel@tonic-gate x_0 = LOAD_LITTLE_32(block + 0); 749*7c478bd9Sstevel@tonic-gate } 750*7c478bd9Sstevel@tonic-gate 751*7c478bd9Sstevel@tonic-gate /* round 1 */ 752*7c478bd9Sstevel@tonic-gate FF(a, b, c, d, x_0, MD5_SHIFT_11, MD5_CONST(0)); /* 1 */ 753*7c478bd9Sstevel@tonic-gate FF(d, a, b, c, x_1, MD5_SHIFT_12, MD5_CONST(1)); /* 2 */ 754*7c478bd9Sstevel@tonic-gate FF(c, d, a, b, x_2, MD5_SHIFT_13, MD5_CONST(2)); /* 3 */ 755*7c478bd9Sstevel@tonic-gate FF(b, c, d, a, x_3, MD5_SHIFT_14, MD5_CONST(3)); /* 4 */ 756*7c478bd9Sstevel@tonic-gate FF(a, b, c, d, x_4, MD5_SHIFT_11, MD5_CONST(4)); /* 5 */ 757*7c478bd9Sstevel@tonic-gate FF(d, a, b, c, x_5, MD5_SHIFT_12, MD5_CONST(5)); /* 6 */ 758*7c478bd9Sstevel@tonic-gate FF(c, d, a, b, x_6, MD5_SHIFT_13, MD5_CONST(6)); /* 7 */ 759*7c478bd9Sstevel@tonic-gate FF(b, c, d, a, x_7, MD5_SHIFT_14, MD5_CONST(7)); /* 8 */ 760*7c478bd9Sstevel@tonic-gate FF(a, b, c, d, x_8, MD5_SHIFT_11, MD5_CONST(8)); /* 9 */ 761*7c478bd9Sstevel@tonic-gate FF(d, a, b, c, x_9, MD5_SHIFT_12, MD5_CONST(9)); /* 10 */ 762*7c478bd9Sstevel@tonic-gate FF(c, d, a, b, x_10, MD5_SHIFT_13, MD5_CONST(10)); /* 11 */ 763*7c478bd9Sstevel@tonic-gate FF(b, c, d, a, x_11, MD5_SHIFT_14, MD5_CONST(11)); /* 12 */ 764*7c478bd9Sstevel@tonic-gate FF(a, b, c, d, x_12, MD5_SHIFT_11, MD5_CONST(12)); /* 13 */ 765*7c478bd9Sstevel@tonic-gate FF(d, a, b, c, x_13, MD5_SHIFT_12, MD5_CONST(13)); /* 14 */ 766*7c478bd9Sstevel@tonic-gate FF(c, d, a, b, x_14, MD5_SHIFT_13, MD5_CONST(14)); /* 15 */ 767*7c478bd9Sstevel@tonic-gate FF(b, c, d, a, x_15, MD5_SHIFT_14, MD5_CONST(15)); /* 16 */ 768*7c478bd9Sstevel@tonic-gate 769*7c478bd9Sstevel@tonic-gate /* round 2 */ 770*7c478bd9Sstevel@tonic-gate GG(a, b, c, d, x_1, MD5_SHIFT_21, MD5_CONST(16)); /* 17 */ 771*7c478bd9Sstevel@tonic-gate GG(d, a, b, c, x_6, MD5_SHIFT_22, MD5_CONST(17)); /* 18 */ 772*7c478bd9Sstevel@tonic-gate GG(c, d, a, b, x_11, MD5_SHIFT_23, MD5_CONST(18)); /* 19 */ 773*7c478bd9Sstevel@tonic-gate GG(b, c, d, a, x_0, MD5_SHIFT_24, MD5_CONST(19)); /* 20 */ 774*7c478bd9Sstevel@tonic-gate GG(a, b, c, d, x_5, MD5_SHIFT_21, MD5_CONST(20)); /* 21 */ 775*7c478bd9Sstevel@tonic-gate GG(d, a, b, c, x_10, MD5_SHIFT_22, MD5_CONST(21)); /* 22 */ 776*7c478bd9Sstevel@tonic-gate GG(c, d, a, b, x_15, MD5_SHIFT_23, MD5_CONST(22)); /* 23 */ 777*7c478bd9Sstevel@tonic-gate GG(b, c, d, a, x_4, MD5_SHIFT_24, MD5_CONST(23)); /* 24 */ 778*7c478bd9Sstevel@tonic-gate GG(a, b, c, d, x_9, MD5_SHIFT_21, MD5_CONST(24)); /* 25 */ 779*7c478bd9Sstevel@tonic-gate GG(d, a, b, c, x_14, MD5_SHIFT_22, MD5_CONST(25)); /* 26 */ 780*7c478bd9Sstevel@tonic-gate GG(c, d, a, b, x_3, MD5_SHIFT_23, MD5_CONST(26)); /* 27 */ 781*7c478bd9Sstevel@tonic-gate GG(b, c, d, a, x_8, MD5_SHIFT_24, MD5_CONST(27)); /* 28 */ 782*7c478bd9Sstevel@tonic-gate GG(a, b, c, d, x_13, MD5_SHIFT_21, MD5_CONST(28)); /* 29 */ 783*7c478bd9Sstevel@tonic-gate GG(d, a, b, c, x_2, MD5_SHIFT_22, MD5_CONST(29)); /* 30 */ 784*7c478bd9Sstevel@tonic-gate GG(c, d, a, b, x_7, MD5_SHIFT_23, MD5_CONST(30)); /* 31 */ 785*7c478bd9Sstevel@tonic-gate GG(b, c, d, a, x_12, MD5_SHIFT_24, MD5_CONST(31)); /* 32 */ 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate /* round 3 */ 788*7c478bd9Sstevel@tonic-gate HH(a, b, c, d, x_5, MD5_SHIFT_31, MD5_CONST(32)); /* 33 */ 789*7c478bd9Sstevel@tonic-gate HH(d, a, b, c, x_8, MD5_SHIFT_32, MD5_CONST(33)); /* 34 */ 790*7c478bd9Sstevel@tonic-gate HH(c, d, a, b, x_11, MD5_SHIFT_33, MD5_CONST(34)); /* 35 */ 791*7c478bd9Sstevel@tonic-gate HH(b, c, d, a, x_14, MD5_SHIFT_34, MD5_CONST(35)); /* 36 */ 792*7c478bd9Sstevel@tonic-gate HH(a, b, c, d, x_1, MD5_SHIFT_31, MD5_CONST(36)); /* 37 */ 793*7c478bd9Sstevel@tonic-gate HH(d, a, b, c, x_4, MD5_SHIFT_32, MD5_CONST(37)); /* 38 */ 794*7c478bd9Sstevel@tonic-gate HH(c, d, a, b, x_7, MD5_SHIFT_33, MD5_CONST(38)); /* 39 */ 795*7c478bd9Sstevel@tonic-gate HH(b, c, d, a, x_10, MD5_SHIFT_34, MD5_CONST(39)); /* 40 */ 796*7c478bd9Sstevel@tonic-gate HH(a, b, c, d, x_13, MD5_SHIFT_31, MD5_CONST(40)); /* 41 */ 797*7c478bd9Sstevel@tonic-gate HH(d, a, b, c, x_0, MD5_SHIFT_32, MD5_CONST(41)); /* 42 */ 798*7c478bd9Sstevel@tonic-gate HH(c, d, a, b, x_3, MD5_SHIFT_33, MD5_CONST(42)); /* 43 */ 799*7c478bd9Sstevel@tonic-gate HH(b, c, d, a, x_6, MD5_SHIFT_34, MD5_CONST(43)); /* 44 */ 800*7c478bd9Sstevel@tonic-gate HH(a, b, c, d, x_9, MD5_SHIFT_31, MD5_CONST(44)); /* 45 */ 801*7c478bd9Sstevel@tonic-gate HH(d, a, b, c, x_12, MD5_SHIFT_32, MD5_CONST(45)); /* 46 */ 802*7c478bd9Sstevel@tonic-gate HH(c, d, a, b, x_15, MD5_SHIFT_33, MD5_CONST(46)); /* 47 */ 803*7c478bd9Sstevel@tonic-gate HH(b, c, d, a, x_2, MD5_SHIFT_34, MD5_CONST(47)); /* 48 */ 804*7c478bd9Sstevel@tonic-gate 805*7c478bd9Sstevel@tonic-gate /* round 4 */ 806*7c478bd9Sstevel@tonic-gate II(a, b, c, d, x_0, MD5_SHIFT_41, MD5_CONST(48)); /* 49 */ 807*7c478bd9Sstevel@tonic-gate II(d, a, b, c, x_7, MD5_SHIFT_42, MD5_CONST(49)); /* 50 */ 808*7c478bd9Sstevel@tonic-gate II(c, d, a, b, x_14, MD5_SHIFT_43, MD5_CONST(50)); /* 51 */ 809*7c478bd9Sstevel@tonic-gate II(b, c, d, a, x_5, MD5_SHIFT_44, MD5_CONST(51)); /* 52 */ 810*7c478bd9Sstevel@tonic-gate II(a, b, c, d, x_12, MD5_SHIFT_41, MD5_CONST(52)); /* 53 */ 811*7c478bd9Sstevel@tonic-gate II(d, a, b, c, x_3, MD5_SHIFT_42, MD5_CONST(53)); /* 54 */ 812*7c478bd9Sstevel@tonic-gate II(c, d, a, b, x_10, MD5_SHIFT_43, MD5_CONST(54)); /* 55 */ 813*7c478bd9Sstevel@tonic-gate II(b, c, d, a, x_1, MD5_SHIFT_44, MD5_CONST(55)); /* 56 */ 814*7c478bd9Sstevel@tonic-gate II(a, b, c, d, x_8, MD5_SHIFT_41, MD5_CONST(56)); /* 57 */ 815*7c478bd9Sstevel@tonic-gate II(d, a, b, c, x_15, MD5_SHIFT_42, MD5_CONST(57)); /* 58 */ 816*7c478bd9Sstevel@tonic-gate II(c, d, a, b, x_6, MD5_SHIFT_43, MD5_CONST(58)); /* 59 */ 817*7c478bd9Sstevel@tonic-gate II(b, c, d, a, x_13, MD5_SHIFT_44, MD5_CONST(59)); /* 60 */ 818*7c478bd9Sstevel@tonic-gate II(a, b, c, d, x_4, MD5_SHIFT_41, MD5_CONST(60)); /* 61 */ 819*7c478bd9Sstevel@tonic-gate II(d, a, b, c, x_11, MD5_SHIFT_42, MD5_CONST(61)); /* 62 */ 820*7c478bd9Sstevel@tonic-gate II(c, d, a, b, x_2, MD5_SHIFT_43, MD5_CONST(62)); /* 63 */ 821*7c478bd9Sstevel@tonic-gate II(b, c, d, a, x_9, MD5_SHIFT_44, MD5_CONST(63)); /* 64 */ 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate ctx->state[0] += a; 824*7c478bd9Sstevel@tonic-gate ctx->state[1] += b; 825*7c478bd9Sstevel@tonic-gate ctx->state[2] += c; 826*7c478bd9Sstevel@tonic-gate ctx->state[3] += d; 827*7c478bd9Sstevel@tonic-gate 828*7c478bd9Sstevel@tonic-gate /* 829*7c478bd9Sstevel@tonic-gate * zeroize sensitive information -- compiler will optimize 830*7c478bd9Sstevel@tonic-gate * this out if everything is kept in registers 831*7c478bd9Sstevel@tonic-gate */ 832*7c478bd9Sstevel@tonic-gate 833*7c478bd9Sstevel@tonic-gate x_0 = x_1 = x_2 = x_3 = x_4 = x_5 = x_6 = x_7 = x_8 = 0; 834*7c478bd9Sstevel@tonic-gate x_9 = x_10 = x_11 = x_12 = x_13 = x_14 = x_15 = 0; 835*7c478bd9Sstevel@tonic-gate } 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate /* 838*7c478bd9Sstevel@tonic-gate * devpro compiler optimization: 839*7c478bd9Sstevel@tonic-gate * 840*7c478bd9Sstevel@tonic-gate * the compiler can generate better code if it knows that `input' and 841*7c478bd9Sstevel@tonic-gate * `output' do not point to the same source. there is no portable 842*7c478bd9Sstevel@tonic-gate * way to tell the compiler this, but the devpro compiler recognizes the 843*7c478bd9Sstevel@tonic-gate * `_Restrict' keyword to indicate this condition. use it if possible. 844*7c478bd9Sstevel@tonic-gate */ 845*7c478bd9Sstevel@tonic-gate 846*7c478bd9Sstevel@tonic-gate #if defined(__RESTRICT) && !defined(__GNUC__) 847*7c478bd9Sstevel@tonic-gate #define restrict _Restrict 848*7c478bd9Sstevel@tonic-gate #else 849*7c478bd9Sstevel@tonic-gate #define restrict /* nothing */ 850*7c478bd9Sstevel@tonic-gate #endif 851*7c478bd9Sstevel@tonic-gate 852*7c478bd9Sstevel@tonic-gate /* 853*7c478bd9Sstevel@tonic-gate * Encode() 854*7c478bd9Sstevel@tonic-gate * 855*7c478bd9Sstevel@tonic-gate * purpose: to convert a list of numbers from big endian to little endian 856*7c478bd9Sstevel@tonic-gate * input: uint8_t * : place to store the converted little endian numbers 857*7c478bd9Sstevel@tonic-gate * uint32_t * : place to get numbers to convert from 858*7c478bd9Sstevel@tonic-gate * size_t : the length of the input in bytes 859*7c478bd9Sstevel@tonic-gate * output: void 860*7c478bd9Sstevel@tonic-gate */ 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate static void 863*7c478bd9Sstevel@tonic-gate Encode(uint8_t *restrict output, uint32_t *restrict input, size_t input_len) 864*7c478bd9Sstevel@tonic-gate { 865*7c478bd9Sstevel@tonic-gate size_t i, j; 866*7c478bd9Sstevel@tonic-gate 867*7c478bd9Sstevel@tonic-gate for (i = 0, j = 0; j < input_len; i++, j += sizeof (uint32_t)) { 868*7c478bd9Sstevel@tonic-gate 869*7c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN 870*7c478bd9Sstevel@tonic-gate 871*7c478bd9Sstevel@tonic-gate #ifdef _MD5_CHECK_ALIGNMENT 872*7c478bd9Sstevel@tonic-gate if ((uintptr_t)output & 0x3) /* Not 4-byte aligned */ 873*7c478bd9Sstevel@tonic-gate bcopy(input + i, output + j, 4); 874*7c478bd9Sstevel@tonic-gate else *(uint32_t *)(output + j) = input[i]; 875*7c478bd9Sstevel@tonic-gate #else 876*7c478bd9Sstevel@tonic-gate *(uint32_t *)(output + j) = input[i]; 877*7c478bd9Sstevel@tonic-gate #endif /* _MD5_CHECK_ALIGNMENT */ 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate #else /* big endian -- will work on little endian, but slowly */ 880*7c478bd9Sstevel@tonic-gate 881*7c478bd9Sstevel@tonic-gate output[j] = input[i] & 0xff; 882*7c478bd9Sstevel@tonic-gate output[j + 1] = (input[i] >> 8) & 0xff; 883*7c478bd9Sstevel@tonic-gate output[j + 2] = (input[i] >> 16) & 0xff; 884*7c478bd9Sstevel@tonic-gate output[j + 3] = (input[i] >> 24) & 0xff; 885*7c478bd9Sstevel@tonic-gate #endif 886*7c478bd9Sstevel@tonic-gate } 887*7c478bd9Sstevel@tonic-gate } 888*7c478bd9Sstevel@tonic-gate 889*7c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT) 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate /* 892*7c478bd9Sstevel@tonic-gate * KCF software provider control entry points. 893*7c478bd9Sstevel@tonic-gate */ 894*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 895*7c478bd9Sstevel@tonic-gate static void 896*7c478bd9Sstevel@tonic-gate md5_provider_status(crypto_provider_handle_t provider, uint_t *status) 897*7c478bd9Sstevel@tonic-gate { 898*7c478bd9Sstevel@tonic-gate *status = CRYPTO_PROVIDER_READY; 899*7c478bd9Sstevel@tonic-gate } 900*7c478bd9Sstevel@tonic-gate 901*7c478bd9Sstevel@tonic-gate /* 902*7c478bd9Sstevel@tonic-gate * KCF software provider digest entry points. 903*7c478bd9Sstevel@tonic-gate */ 904*7c478bd9Sstevel@tonic-gate 905*7c478bd9Sstevel@tonic-gate static int 906*7c478bd9Sstevel@tonic-gate md5_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 907*7c478bd9Sstevel@tonic-gate crypto_req_handle_t req) 908*7c478bd9Sstevel@tonic-gate { 909*7c478bd9Sstevel@tonic-gate if (mechanism->cm_type != MD5_MECH_INFO_TYPE) 910*7c478bd9Sstevel@tonic-gate return (CRYPTO_MECHANISM_INVALID); 911*7c478bd9Sstevel@tonic-gate 912*7c478bd9Sstevel@tonic-gate /* 913*7c478bd9Sstevel@tonic-gate * Allocate and initialize MD5 context. 914*7c478bd9Sstevel@tonic-gate */ 915*7c478bd9Sstevel@tonic-gate ctx->cc_provider_private = kmem_alloc(sizeof (md5_ctx_t), 916*7c478bd9Sstevel@tonic-gate crypto_kmflag(req)); 917*7c478bd9Sstevel@tonic-gate if (ctx->cc_provider_private == NULL) 918*7c478bd9Sstevel@tonic-gate return (CRYPTO_HOST_MEMORY); 919*7c478bd9Sstevel@tonic-gate 920*7c478bd9Sstevel@tonic-gate PROV_MD5_CTX(ctx)->mc_mech_type = MD5_MECH_INFO_TYPE; 921*7c478bd9Sstevel@tonic-gate MD5Init(&PROV_MD5_CTX(ctx)->mc_md5_ctx); 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 924*7c478bd9Sstevel@tonic-gate } 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate /* 927*7c478bd9Sstevel@tonic-gate * Helper MD5 digest update function for uio data. 928*7c478bd9Sstevel@tonic-gate */ 929*7c478bd9Sstevel@tonic-gate static int 930*7c478bd9Sstevel@tonic-gate md5_digest_update_uio(MD5_CTX *md5_ctx, crypto_data_t *data) 931*7c478bd9Sstevel@tonic-gate { 932*7c478bd9Sstevel@tonic-gate off_t offset = data->cd_offset; 933*7c478bd9Sstevel@tonic-gate size_t length = data->cd_length; 934*7c478bd9Sstevel@tonic-gate uint_t vec_idx; 935*7c478bd9Sstevel@tonic-gate size_t cur_len; 936*7c478bd9Sstevel@tonic-gate 937*7c478bd9Sstevel@tonic-gate /* we support only kernel buffer */ 938*7c478bd9Sstevel@tonic-gate if (data->cd_uio->uio_segflg != UIO_SYSSPACE) 939*7c478bd9Sstevel@tonic-gate return (CRYPTO_ARGUMENTS_BAD); 940*7c478bd9Sstevel@tonic-gate 941*7c478bd9Sstevel@tonic-gate /* 942*7c478bd9Sstevel@tonic-gate * Jump to the first iovec containing data to be 943*7c478bd9Sstevel@tonic-gate * digested. 944*7c478bd9Sstevel@tonic-gate */ 945*7c478bd9Sstevel@tonic-gate for (vec_idx = 0; vec_idx < data->cd_uio->uio_iovcnt && 946*7c478bd9Sstevel@tonic-gate offset >= data->cd_uio->uio_iov[vec_idx].iov_len; 947*7c478bd9Sstevel@tonic-gate offset -= data->cd_uio->uio_iov[vec_idx++].iov_len); 948*7c478bd9Sstevel@tonic-gate if (vec_idx == data->cd_uio->uio_iovcnt) { 949*7c478bd9Sstevel@tonic-gate /* 950*7c478bd9Sstevel@tonic-gate * The caller specified an offset that is larger than the 951*7c478bd9Sstevel@tonic-gate * total size of the buffers it provided. 952*7c478bd9Sstevel@tonic-gate */ 953*7c478bd9Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 954*7c478bd9Sstevel@tonic-gate } 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate /* 957*7c478bd9Sstevel@tonic-gate * Now do the digesting on the iovecs. 958*7c478bd9Sstevel@tonic-gate */ 959*7c478bd9Sstevel@tonic-gate while (vec_idx < data->cd_uio->uio_iovcnt && length > 0) { 960*7c478bd9Sstevel@tonic-gate cur_len = MIN(data->cd_uio->uio_iov[vec_idx].iov_len - 961*7c478bd9Sstevel@tonic-gate offset, length); 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate MD5Update(md5_ctx, data->cd_uio->uio_iov[vec_idx].iov_base + 964*7c478bd9Sstevel@tonic-gate offset, cur_len); 965*7c478bd9Sstevel@tonic-gate 966*7c478bd9Sstevel@tonic-gate length -= cur_len; 967*7c478bd9Sstevel@tonic-gate vec_idx++; 968*7c478bd9Sstevel@tonic-gate offset = 0; 969*7c478bd9Sstevel@tonic-gate } 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate if (vec_idx == data->cd_uio->uio_iovcnt && length > 0) { 972*7c478bd9Sstevel@tonic-gate /* 973*7c478bd9Sstevel@tonic-gate * The end of the specified iovec's was reached but 974*7c478bd9Sstevel@tonic-gate * the length requested could not be processed, i.e. 975*7c478bd9Sstevel@tonic-gate * The caller requested to digest more data than it provided. 976*7c478bd9Sstevel@tonic-gate */ 977*7c478bd9Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 978*7c478bd9Sstevel@tonic-gate } 979*7c478bd9Sstevel@tonic-gate 980*7c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 981*7c478bd9Sstevel@tonic-gate } 982*7c478bd9Sstevel@tonic-gate 983*7c478bd9Sstevel@tonic-gate /* 984*7c478bd9Sstevel@tonic-gate * Helper MD5 digest final function for uio data. 985*7c478bd9Sstevel@tonic-gate * digest_len is the length of the desired digest. If digest_len 986*7c478bd9Sstevel@tonic-gate * is smaller than the default MD5 digest length, the caller 987*7c478bd9Sstevel@tonic-gate * must pass a scratch buffer, digest_scratch, which must 988*7c478bd9Sstevel@tonic-gate * be at least MD5_DIGEST_LENGTH bytes. 989*7c478bd9Sstevel@tonic-gate */ 990*7c478bd9Sstevel@tonic-gate static int 991*7c478bd9Sstevel@tonic-gate md5_digest_final_uio(MD5_CTX *md5_ctx, crypto_data_t *digest, 992*7c478bd9Sstevel@tonic-gate ulong_t digest_len, uchar_t *digest_scratch) 993*7c478bd9Sstevel@tonic-gate { 994*7c478bd9Sstevel@tonic-gate off_t offset = digest->cd_offset; 995*7c478bd9Sstevel@tonic-gate uint_t vec_idx; 996*7c478bd9Sstevel@tonic-gate 997*7c478bd9Sstevel@tonic-gate /* we support only kernel buffer */ 998*7c478bd9Sstevel@tonic-gate if (digest->cd_uio->uio_segflg != UIO_SYSSPACE) 999*7c478bd9Sstevel@tonic-gate return (CRYPTO_ARGUMENTS_BAD); 1000*7c478bd9Sstevel@tonic-gate 1001*7c478bd9Sstevel@tonic-gate /* 1002*7c478bd9Sstevel@tonic-gate * Jump to the first iovec containing ptr to the digest to 1003*7c478bd9Sstevel@tonic-gate * be returned. 1004*7c478bd9Sstevel@tonic-gate */ 1005*7c478bd9Sstevel@tonic-gate for (vec_idx = 0; offset >= digest->cd_uio->uio_iov[vec_idx].iov_len && 1006*7c478bd9Sstevel@tonic-gate vec_idx < digest->cd_uio->uio_iovcnt; 1007*7c478bd9Sstevel@tonic-gate offset -= digest->cd_uio->uio_iov[vec_idx++].iov_len); 1008*7c478bd9Sstevel@tonic-gate if (vec_idx == digest->cd_uio->uio_iovcnt) { 1009*7c478bd9Sstevel@tonic-gate /* 1010*7c478bd9Sstevel@tonic-gate * The caller specified an offset that is 1011*7c478bd9Sstevel@tonic-gate * larger than the total size of the buffers 1012*7c478bd9Sstevel@tonic-gate * it provided. 1013*7c478bd9Sstevel@tonic-gate */ 1014*7c478bd9Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 1015*7c478bd9Sstevel@tonic-gate } 1016*7c478bd9Sstevel@tonic-gate 1017*7c478bd9Sstevel@tonic-gate if (offset + digest_len <= 1018*7c478bd9Sstevel@tonic-gate digest->cd_uio->uio_iov[vec_idx].iov_len) { 1019*7c478bd9Sstevel@tonic-gate /* 1020*7c478bd9Sstevel@tonic-gate * The computed MD5 digest will fit in the current 1021*7c478bd9Sstevel@tonic-gate * iovec. 1022*7c478bd9Sstevel@tonic-gate */ 1023*7c478bd9Sstevel@tonic-gate if (digest_len != MD5_DIGEST_LENGTH) { 1024*7c478bd9Sstevel@tonic-gate /* 1025*7c478bd9Sstevel@tonic-gate * The caller requested a short digest. Digest 1026*7c478bd9Sstevel@tonic-gate * into a scratch buffer and return to 1027*7c478bd9Sstevel@tonic-gate * the user only what was requested. 1028*7c478bd9Sstevel@tonic-gate */ 1029*7c478bd9Sstevel@tonic-gate MD5Final(digest_scratch, md5_ctx); 1030*7c478bd9Sstevel@tonic-gate bcopy(digest_scratch, (uchar_t *)digest-> 1031*7c478bd9Sstevel@tonic-gate cd_uio->uio_iov[vec_idx].iov_base + offset, 1032*7c478bd9Sstevel@tonic-gate digest_len); 1033*7c478bd9Sstevel@tonic-gate } else { 1034*7c478bd9Sstevel@tonic-gate MD5Final((uchar_t *)digest-> 1035*7c478bd9Sstevel@tonic-gate cd_uio->uio_iov[vec_idx].iov_base + offset, 1036*7c478bd9Sstevel@tonic-gate md5_ctx); 1037*7c478bd9Sstevel@tonic-gate } 1038*7c478bd9Sstevel@tonic-gate } else { 1039*7c478bd9Sstevel@tonic-gate /* 1040*7c478bd9Sstevel@tonic-gate * The computed digest will be crossing one or more iovec's. 1041*7c478bd9Sstevel@tonic-gate * This is bad performance-wise but we need to support it. 1042*7c478bd9Sstevel@tonic-gate * Allocate a small scratch buffer on the stack and 1043*7c478bd9Sstevel@tonic-gate * copy it piece meal to the specified digest iovec's. 1044*7c478bd9Sstevel@tonic-gate */ 1045*7c478bd9Sstevel@tonic-gate uchar_t digest_tmp[MD5_DIGEST_LENGTH]; 1046*7c478bd9Sstevel@tonic-gate off_t scratch_offset = 0; 1047*7c478bd9Sstevel@tonic-gate size_t length = digest_len; 1048*7c478bd9Sstevel@tonic-gate size_t cur_len; 1049*7c478bd9Sstevel@tonic-gate 1050*7c478bd9Sstevel@tonic-gate MD5Final(digest_tmp, md5_ctx); 1051*7c478bd9Sstevel@tonic-gate 1052*7c478bd9Sstevel@tonic-gate while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) { 1053*7c478bd9Sstevel@tonic-gate cur_len = MIN(digest->cd_uio->uio_iov[vec_idx].iov_len - 1054*7c478bd9Sstevel@tonic-gate offset, length); 1055*7c478bd9Sstevel@tonic-gate bcopy(digest_tmp + scratch_offset, 1056*7c478bd9Sstevel@tonic-gate digest->cd_uio->uio_iov[vec_idx].iov_base + offset, 1057*7c478bd9Sstevel@tonic-gate cur_len); 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate length -= cur_len; 1060*7c478bd9Sstevel@tonic-gate vec_idx++; 1061*7c478bd9Sstevel@tonic-gate scratch_offset += cur_len; 1062*7c478bd9Sstevel@tonic-gate offset = 0; 1063*7c478bd9Sstevel@tonic-gate } 1064*7c478bd9Sstevel@tonic-gate 1065*7c478bd9Sstevel@tonic-gate if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) { 1066*7c478bd9Sstevel@tonic-gate /* 1067*7c478bd9Sstevel@tonic-gate * The end of the specified iovec's was reached but 1068*7c478bd9Sstevel@tonic-gate * the length requested could not be processed, i.e. 1069*7c478bd9Sstevel@tonic-gate * The caller requested to digest more data than it 1070*7c478bd9Sstevel@tonic-gate * provided. 1071*7c478bd9Sstevel@tonic-gate */ 1072*7c478bd9Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 1073*7c478bd9Sstevel@tonic-gate } 1074*7c478bd9Sstevel@tonic-gate } 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 1077*7c478bd9Sstevel@tonic-gate } 1078*7c478bd9Sstevel@tonic-gate 1079*7c478bd9Sstevel@tonic-gate /* 1080*7c478bd9Sstevel@tonic-gate * Helper MD5 digest update for mblk's. 1081*7c478bd9Sstevel@tonic-gate */ 1082*7c478bd9Sstevel@tonic-gate static int 1083*7c478bd9Sstevel@tonic-gate md5_digest_update_mblk(MD5_CTX *md5_ctx, crypto_data_t *data) 1084*7c478bd9Sstevel@tonic-gate { 1085*7c478bd9Sstevel@tonic-gate off_t offset = data->cd_offset; 1086*7c478bd9Sstevel@tonic-gate size_t length = data->cd_length; 1087*7c478bd9Sstevel@tonic-gate mblk_t *mp; 1088*7c478bd9Sstevel@tonic-gate size_t cur_len; 1089*7c478bd9Sstevel@tonic-gate 1090*7c478bd9Sstevel@tonic-gate /* 1091*7c478bd9Sstevel@tonic-gate * Jump to the first mblk_t containing data to be digested. 1092*7c478bd9Sstevel@tonic-gate */ 1093*7c478bd9Sstevel@tonic-gate for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp); 1094*7c478bd9Sstevel@tonic-gate offset -= MBLKL(mp), mp = mp->b_cont); 1095*7c478bd9Sstevel@tonic-gate if (mp == NULL) { 1096*7c478bd9Sstevel@tonic-gate /* 1097*7c478bd9Sstevel@tonic-gate * The caller specified an offset that is larger than the 1098*7c478bd9Sstevel@tonic-gate * total size of the buffers it provided. 1099*7c478bd9Sstevel@tonic-gate */ 1100*7c478bd9Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 1101*7c478bd9Sstevel@tonic-gate } 1102*7c478bd9Sstevel@tonic-gate 1103*7c478bd9Sstevel@tonic-gate /* 1104*7c478bd9Sstevel@tonic-gate * Now do the digesting on the mblk chain. 1105*7c478bd9Sstevel@tonic-gate */ 1106*7c478bd9Sstevel@tonic-gate while (mp != NULL && length > 0) { 1107*7c478bd9Sstevel@tonic-gate cur_len = MIN(MBLKL(mp) - offset, length); 1108*7c478bd9Sstevel@tonic-gate MD5Update(md5_ctx, mp->b_rptr + offset, cur_len); 1109*7c478bd9Sstevel@tonic-gate length -= cur_len; 1110*7c478bd9Sstevel@tonic-gate offset = 0; 1111*7c478bd9Sstevel@tonic-gate mp = mp->b_cont; 1112*7c478bd9Sstevel@tonic-gate } 1113*7c478bd9Sstevel@tonic-gate 1114*7c478bd9Sstevel@tonic-gate if (mp == NULL && length > 0) { 1115*7c478bd9Sstevel@tonic-gate /* 1116*7c478bd9Sstevel@tonic-gate * The end of the mblk was reached but the length requested 1117*7c478bd9Sstevel@tonic-gate * could not be processed, i.e. The caller requested 1118*7c478bd9Sstevel@tonic-gate * to digest more data than it provided. 1119*7c478bd9Sstevel@tonic-gate */ 1120*7c478bd9Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 1121*7c478bd9Sstevel@tonic-gate } 1122*7c478bd9Sstevel@tonic-gate 1123*7c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 1124*7c478bd9Sstevel@tonic-gate } 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate /* 1127*7c478bd9Sstevel@tonic-gate * Helper MD5 digest final for mblk's. 1128*7c478bd9Sstevel@tonic-gate * digest_len is the length of the desired digest. If digest_len 1129*7c478bd9Sstevel@tonic-gate * is smaller than the default MD5 digest length, the caller 1130*7c478bd9Sstevel@tonic-gate * must pass a scratch buffer, digest_scratch, which must 1131*7c478bd9Sstevel@tonic-gate * be at least MD5_DIGEST_LENGTH bytes. 1132*7c478bd9Sstevel@tonic-gate */ 1133*7c478bd9Sstevel@tonic-gate static int 1134*7c478bd9Sstevel@tonic-gate md5_digest_final_mblk(MD5_CTX *md5_ctx, crypto_data_t *digest, 1135*7c478bd9Sstevel@tonic-gate ulong_t digest_len, uchar_t *digest_scratch) 1136*7c478bd9Sstevel@tonic-gate { 1137*7c478bd9Sstevel@tonic-gate off_t offset = digest->cd_offset; 1138*7c478bd9Sstevel@tonic-gate mblk_t *mp; 1139*7c478bd9Sstevel@tonic-gate 1140*7c478bd9Sstevel@tonic-gate /* 1141*7c478bd9Sstevel@tonic-gate * Jump to the first mblk_t that will be used to store the digest. 1142*7c478bd9Sstevel@tonic-gate */ 1143*7c478bd9Sstevel@tonic-gate for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp); 1144*7c478bd9Sstevel@tonic-gate offset -= MBLKL(mp), mp = mp->b_cont); 1145*7c478bd9Sstevel@tonic-gate if (mp == NULL) { 1146*7c478bd9Sstevel@tonic-gate /* 1147*7c478bd9Sstevel@tonic-gate * The caller specified an offset that is larger than the 1148*7c478bd9Sstevel@tonic-gate * total size of the buffers it provided. 1149*7c478bd9Sstevel@tonic-gate */ 1150*7c478bd9Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 1151*7c478bd9Sstevel@tonic-gate } 1152*7c478bd9Sstevel@tonic-gate 1153*7c478bd9Sstevel@tonic-gate if (offset + digest_len <= MBLKL(mp)) { 1154*7c478bd9Sstevel@tonic-gate /* 1155*7c478bd9Sstevel@tonic-gate * The computed MD5 digest will fit in the current mblk. 1156*7c478bd9Sstevel@tonic-gate * Do the MD5Final() in-place. 1157*7c478bd9Sstevel@tonic-gate */ 1158*7c478bd9Sstevel@tonic-gate if (digest_len != MD5_DIGEST_LENGTH) { 1159*7c478bd9Sstevel@tonic-gate /* 1160*7c478bd9Sstevel@tonic-gate * The caller requested a short digest. Digest 1161*7c478bd9Sstevel@tonic-gate * into a scratch buffer and return to 1162*7c478bd9Sstevel@tonic-gate * the user only what was requested. 1163*7c478bd9Sstevel@tonic-gate */ 1164*7c478bd9Sstevel@tonic-gate MD5Final(digest_scratch, md5_ctx); 1165*7c478bd9Sstevel@tonic-gate bcopy(digest_scratch, mp->b_rptr + offset, digest_len); 1166*7c478bd9Sstevel@tonic-gate } else { 1167*7c478bd9Sstevel@tonic-gate MD5Final(mp->b_rptr + offset, md5_ctx); 1168*7c478bd9Sstevel@tonic-gate } 1169*7c478bd9Sstevel@tonic-gate } else { 1170*7c478bd9Sstevel@tonic-gate /* 1171*7c478bd9Sstevel@tonic-gate * The computed digest will be crossing one or more mblk's. 1172*7c478bd9Sstevel@tonic-gate * This is bad performance-wise but we need to support it. 1173*7c478bd9Sstevel@tonic-gate * Allocate a small scratch buffer on the stack and 1174*7c478bd9Sstevel@tonic-gate * copy it piece meal to the specified digest iovec's. 1175*7c478bd9Sstevel@tonic-gate */ 1176*7c478bd9Sstevel@tonic-gate uchar_t digest_tmp[MD5_DIGEST_LENGTH]; 1177*7c478bd9Sstevel@tonic-gate off_t scratch_offset = 0; 1178*7c478bd9Sstevel@tonic-gate size_t length = digest_len; 1179*7c478bd9Sstevel@tonic-gate size_t cur_len; 1180*7c478bd9Sstevel@tonic-gate 1181*7c478bd9Sstevel@tonic-gate MD5Final(digest_tmp, md5_ctx); 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate while (mp != NULL && length > 0) { 1184*7c478bd9Sstevel@tonic-gate cur_len = MIN(MBLKL(mp) - offset, length); 1185*7c478bd9Sstevel@tonic-gate bcopy(digest_tmp + scratch_offset, 1186*7c478bd9Sstevel@tonic-gate mp->b_rptr + offset, cur_len); 1187*7c478bd9Sstevel@tonic-gate 1188*7c478bd9Sstevel@tonic-gate length -= cur_len; 1189*7c478bd9Sstevel@tonic-gate mp = mp->b_cont; 1190*7c478bd9Sstevel@tonic-gate scratch_offset += cur_len; 1191*7c478bd9Sstevel@tonic-gate offset = 0; 1192*7c478bd9Sstevel@tonic-gate } 1193*7c478bd9Sstevel@tonic-gate 1194*7c478bd9Sstevel@tonic-gate if (mp == NULL && length > 0) { 1195*7c478bd9Sstevel@tonic-gate /* 1196*7c478bd9Sstevel@tonic-gate * The end of the specified mblk was reached but 1197*7c478bd9Sstevel@tonic-gate * the length requested could not be processed, i.e. 1198*7c478bd9Sstevel@tonic-gate * The caller requested to digest more data than it 1199*7c478bd9Sstevel@tonic-gate * provided. 1200*7c478bd9Sstevel@tonic-gate */ 1201*7c478bd9Sstevel@tonic-gate return (CRYPTO_DATA_LEN_RANGE); 1202*7c478bd9Sstevel@tonic-gate } 1203*7c478bd9Sstevel@tonic-gate } 1204*7c478bd9Sstevel@tonic-gate 1205*7c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 1206*7c478bd9Sstevel@tonic-gate } 1207*7c478bd9Sstevel@tonic-gate 1208*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1209*7c478bd9Sstevel@tonic-gate static int 1210*7c478bd9Sstevel@tonic-gate md5_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest, 1211*7c478bd9Sstevel@tonic-gate crypto_req_handle_t req) 1212*7c478bd9Sstevel@tonic-gate { 1213*7c478bd9Sstevel@tonic-gate int ret = CRYPTO_SUCCESS; 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate ASSERT(ctx->cc_provider_private != NULL); 1216*7c478bd9Sstevel@tonic-gate 1217*7c478bd9Sstevel@tonic-gate /* 1218*7c478bd9Sstevel@tonic-gate * We need to just return the length needed to store the output. 1219*7c478bd9Sstevel@tonic-gate * We should not destroy the context for the following cases. 1220*7c478bd9Sstevel@tonic-gate */ 1221*7c478bd9Sstevel@tonic-gate if ((digest->cd_length == 0) || 1222*7c478bd9Sstevel@tonic-gate (digest->cd_length < MD5_DIGEST_LENGTH)) { 1223*7c478bd9Sstevel@tonic-gate digest->cd_length = MD5_DIGEST_LENGTH; 1224*7c478bd9Sstevel@tonic-gate return (CRYPTO_BUFFER_TOO_SMALL); 1225*7c478bd9Sstevel@tonic-gate } 1226*7c478bd9Sstevel@tonic-gate 1227*7c478bd9Sstevel@tonic-gate /* 1228*7c478bd9Sstevel@tonic-gate * Do the MD5 update on the specified input data. 1229*7c478bd9Sstevel@tonic-gate */ 1230*7c478bd9Sstevel@tonic-gate switch (data->cd_format) { 1231*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: 1232*7c478bd9Sstevel@tonic-gate MD5Update(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 1233*7c478bd9Sstevel@tonic-gate data->cd_raw.iov_base + data->cd_offset, 1234*7c478bd9Sstevel@tonic-gate data->cd_length); 1235*7c478bd9Sstevel@tonic-gate break; 1236*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: 1237*7c478bd9Sstevel@tonic-gate ret = md5_digest_update_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 1238*7c478bd9Sstevel@tonic-gate data); 1239*7c478bd9Sstevel@tonic-gate break; 1240*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: 1241*7c478bd9Sstevel@tonic-gate ret = md5_digest_update_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 1242*7c478bd9Sstevel@tonic-gate data); 1243*7c478bd9Sstevel@tonic-gate break; 1244*7c478bd9Sstevel@tonic-gate default: 1245*7c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; 1246*7c478bd9Sstevel@tonic-gate } 1247*7c478bd9Sstevel@tonic-gate 1248*7c478bd9Sstevel@tonic-gate if (ret != CRYPTO_SUCCESS) { 1249*7c478bd9Sstevel@tonic-gate /* the update failed, free context and bail */ 1250*7c478bd9Sstevel@tonic-gate kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t)); 1251*7c478bd9Sstevel@tonic-gate ctx->cc_provider_private = NULL; 1252*7c478bd9Sstevel@tonic-gate digest->cd_length = 0; 1253*7c478bd9Sstevel@tonic-gate return (ret); 1254*7c478bd9Sstevel@tonic-gate } 1255*7c478bd9Sstevel@tonic-gate 1256*7c478bd9Sstevel@tonic-gate /* 1257*7c478bd9Sstevel@tonic-gate * Do an MD5 final, must be done separately since the digest 1258*7c478bd9Sstevel@tonic-gate * type can be different than the input data type. 1259*7c478bd9Sstevel@tonic-gate */ 1260*7c478bd9Sstevel@tonic-gate switch (digest->cd_format) { 1261*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: 1262*7c478bd9Sstevel@tonic-gate MD5Final((unsigned char *)digest->cd_raw.iov_base + 1263*7c478bd9Sstevel@tonic-gate digest->cd_offset, &PROV_MD5_CTX(ctx)->mc_md5_ctx); 1264*7c478bd9Sstevel@tonic-gate break; 1265*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: 1266*7c478bd9Sstevel@tonic-gate ret = md5_digest_final_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 1267*7c478bd9Sstevel@tonic-gate digest, MD5_DIGEST_LENGTH, NULL); 1268*7c478bd9Sstevel@tonic-gate break; 1269*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: 1270*7c478bd9Sstevel@tonic-gate ret = md5_digest_final_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 1271*7c478bd9Sstevel@tonic-gate digest, MD5_DIGEST_LENGTH, NULL); 1272*7c478bd9Sstevel@tonic-gate break; 1273*7c478bd9Sstevel@tonic-gate default: 1274*7c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; 1275*7c478bd9Sstevel@tonic-gate } 1276*7c478bd9Sstevel@tonic-gate 1277*7c478bd9Sstevel@tonic-gate /* all done, free context and return */ 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate if (ret == CRYPTO_SUCCESS) { 1280*7c478bd9Sstevel@tonic-gate digest->cd_length = MD5_DIGEST_LENGTH; 1281*7c478bd9Sstevel@tonic-gate } else { 1282*7c478bd9Sstevel@tonic-gate digest->cd_length = 0; 1283*7c478bd9Sstevel@tonic-gate } 1284*7c478bd9Sstevel@tonic-gate 1285*7c478bd9Sstevel@tonic-gate kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t)); 1286*7c478bd9Sstevel@tonic-gate ctx->cc_provider_private = NULL; 1287*7c478bd9Sstevel@tonic-gate return (ret); 1288*7c478bd9Sstevel@tonic-gate } 1289*7c478bd9Sstevel@tonic-gate 1290*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1291*7c478bd9Sstevel@tonic-gate static int 1292*7c478bd9Sstevel@tonic-gate md5_digest_update(crypto_ctx_t *ctx, crypto_data_t *data, 1293*7c478bd9Sstevel@tonic-gate crypto_req_handle_t req) 1294*7c478bd9Sstevel@tonic-gate { 1295*7c478bd9Sstevel@tonic-gate int ret = CRYPTO_SUCCESS; 1296*7c478bd9Sstevel@tonic-gate 1297*7c478bd9Sstevel@tonic-gate ASSERT(ctx->cc_provider_private != NULL); 1298*7c478bd9Sstevel@tonic-gate 1299*7c478bd9Sstevel@tonic-gate /* 1300*7c478bd9Sstevel@tonic-gate * Do the MD5 update on the specified input data. 1301*7c478bd9Sstevel@tonic-gate */ 1302*7c478bd9Sstevel@tonic-gate switch (data->cd_format) { 1303*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: 1304*7c478bd9Sstevel@tonic-gate MD5Update(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 1305*7c478bd9Sstevel@tonic-gate data->cd_raw.iov_base + data->cd_offset, 1306*7c478bd9Sstevel@tonic-gate data->cd_length); 1307*7c478bd9Sstevel@tonic-gate break; 1308*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: 1309*7c478bd9Sstevel@tonic-gate ret = md5_digest_update_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 1310*7c478bd9Sstevel@tonic-gate data); 1311*7c478bd9Sstevel@tonic-gate break; 1312*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: 1313*7c478bd9Sstevel@tonic-gate ret = md5_digest_update_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 1314*7c478bd9Sstevel@tonic-gate data); 1315*7c478bd9Sstevel@tonic-gate break; 1316*7c478bd9Sstevel@tonic-gate default: 1317*7c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; 1318*7c478bd9Sstevel@tonic-gate } 1319*7c478bd9Sstevel@tonic-gate 1320*7c478bd9Sstevel@tonic-gate return (ret); 1321*7c478bd9Sstevel@tonic-gate } 1322*7c478bd9Sstevel@tonic-gate 1323*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1324*7c478bd9Sstevel@tonic-gate static int 1325*7c478bd9Sstevel@tonic-gate md5_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest, 1326*7c478bd9Sstevel@tonic-gate crypto_req_handle_t req) 1327*7c478bd9Sstevel@tonic-gate { 1328*7c478bd9Sstevel@tonic-gate int ret = CRYPTO_SUCCESS; 1329*7c478bd9Sstevel@tonic-gate 1330*7c478bd9Sstevel@tonic-gate ASSERT(ctx->cc_provider_private != NULL); 1331*7c478bd9Sstevel@tonic-gate 1332*7c478bd9Sstevel@tonic-gate /* 1333*7c478bd9Sstevel@tonic-gate * We need to just return the length needed to store the output. 1334*7c478bd9Sstevel@tonic-gate * We should not destroy the context for the following cases. 1335*7c478bd9Sstevel@tonic-gate */ 1336*7c478bd9Sstevel@tonic-gate if ((digest->cd_length == 0) || 1337*7c478bd9Sstevel@tonic-gate (digest->cd_length < MD5_DIGEST_LENGTH)) { 1338*7c478bd9Sstevel@tonic-gate digest->cd_length = MD5_DIGEST_LENGTH; 1339*7c478bd9Sstevel@tonic-gate return (CRYPTO_BUFFER_TOO_SMALL); 1340*7c478bd9Sstevel@tonic-gate } 1341*7c478bd9Sstevel@tonic-gate 1342*7c478bd9Sstevel@tonic-gate /* 1343*7c478bd9Sstevel@tonic-gate * Do an MD5 final. 1344*7c478bd9Sstevel@tonic-gate */ 1345*7c478bd9Sstevel@tonic-gate switch (digest->cd_format) { 1346*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: 1347*7c478bd9Sstevel@tonic-gate MD5Final((unsigned char *)digest->cd_raw.iov_base + 1348*7c478bd9Sstevel@tonic-gate digest->cd_offset, &PROV_MD5_CTX(ctx)->mc_md5_ctx); 1349*7c478bd9Sstevel@tonic-gate break; 1350*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: 1351*7c478bd9Sstevel@tonic-gate ret = md5_digest_final_uio(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 1352*7c478bd9Sstevel@tonic-gate digest, MD5_DIGEST_LENGTH, NULL); 1353*7c478bd9Sstevel@tonic-gate break; 1354*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: 1355*7c478bd9Sstevel@tonic-gate ret = md5_digest_final_mblk(&PROV_MD5_CTX(ctx)->mc_md5_ctx, 1356*7c478bd9Sstevel@tonic-gate digest, MD5_DIGEST_LENGTH, NULL); 1357*7c478bd9Sstevel@tonic-gate break; 1358*7c478bd9Sstevel@tonic-gate default: 1359*7c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; 1360*7c478bd9Sstevel@tonic-gate } 1361*7c478bd9Sstevel@tonic-gate 1362*7c478bd9Sstevel@tonic-gate /* all done, free context and return */ 1363*7c478bd9Sstevel@tonic-gate 1364*7c478bd9Sstevel@tonic-gate if (ret == CRYPTO_SUCCESS) { 1365*7c478bd9Sstevel@tonic-gate digest->cd_length = MD5_DIGEST_LENGTH; 1366*7c478bd9Sstevel@tonic-gate } else { 1367*7c478bd9Sstevel@tonic-gate digest->cd_length = 0; 1368*7c478bd9Sstevel@tonic-gate } 1369*7c478bd9Sstevel@tonic-gate 1370*7c478bd9Sstevel@tonic-gate kmem_free(ctx->cc_provider_private, sizeof (md5_ctx_t)); 1371*7c478bd9Sstevel@tonic-gate ctx->cc_provider_private = NULL; 1372*7c478bd9Sstevel@tonic-gate 1373*7c478bd9Sstevel@tonic-gate return (ret); 1374*7c478bd9Sstevel@tonic-gate } 1375*7c478bd9Sstevel@tonic-gate 1376*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1377*7c478bd9Sstevel@tonic-gate static int 1378*7c478bd9Sstevel@tonic-gate md5_digest_atomic(crypto_provider_handle_t provider, 1379*7c478bd9Sstevel@tonic-gate crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 1380*7c478bd9Sstevel@tonic-gate crypto_data_t *data, crypto_data_t *digest, 1381*7c478bd9Sstevel@tonic-gate crypto_req_handle_t req) 1382*7c478bd9Sstevel@tonic-gate { 1383*7c478bd9Sstevel@tonic-gate int ret = CRYPTO_SUCCESS; 1384*7c478bd9Sstevel@tonic-gate MD5_CTX md5_ctx; 1385*7c478bd9Sstevel@tonic-gate 1386*7c478bd9Sstevel@tonic-gate if (mechanism->cm_type != MD5_MECH_INFO_TYPE) 1387*7c478bd9Sstevel@tonic-gate return (CRYPTO_MECHANISM_INVALID); 1388*7c478bd9Sstevel@tonic-gate 1389*7c478bd9Sstevel@tonic-gate /* 1390*7c478bd9Sstevel@tonic-gate * Do the MD5 init. 1391*7c478bd9Sstevel@tonic-gate */ 1392*7c478bd9Sstevel@tonic-gate MD5Init(&md5_ctx); 1393*7c478bd9Sstevel@tonic-gate 1394*7c478bd9Sstevel@tonic-gate /* 1395*7c478bd9Sstevel@tonic-gate * Do the MD5 update on the specified input data. 1396*7c478bd9Sstevel@tonic-gate */ 1397*7c478bd9Sstevel@tonic-gate switch (data->cd_format) { 1398*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: 1399*7c478bd9Sstevel@tonic-gate MD5Update(&md5_ctx, data->cd_raw.iov_base + data->cd_offset, 1400*7c478bd9Sstevel@tonic-gate data->cd_length); 1401*7c478bd9Sstevel@tonic-gate break; 1402*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: 1403*7c478bd9Sstevel@tonic-gate ret = md5_digest_update_uio(&md5_ctx, data); 1404*7c478bd9Sstevel@tonic-gate break; 1405*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: 1406*7c478bd9Sstevel@tonic-gate ret = md5_digest_update_mblk(&md5_ctx, data); 1407*7c478bd9Sstevel@tonic-gate break; 1408*7c478bd9Sstevel@tonic-gate default: 1409*7c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; 1410*7c478bd9Sstevel@tonic-gate } 1411*7c478bd9Sstevel@tonic-gate 1412*7c478bd9Sstevel@tonic-gate if (ret != CRYPTO_SUCCESS) { 1413*7c478bd9Sstevel@tonic-gate /* the update failed, bail */ 1414*7c478bd9Sstevel@tonic-gate digest->cd_length = 0; 1415*7c478bd9Sstevel@tonic-gate return (ret); 1416*7c478bd9Sstevel@tonic-gate } 1417*7c478bd9Sstevel@tonic-gate 1418*7c478bd9Sstevel@tonic-gate /* 1419*7c478bd9Sstevel@tonic-gate * Do an MD5 final, must be done separately since the digest 1420*7c478bd9Sstevel@tonic-gate * type can be different than the input data type. 1421*7c478bd9Sstevel@tonic-gate */ 1422*7c478bd9Sstevel@tonic-gate switch (digest->cd_format) { 1423*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: 1424*7c478bd9Sstevel@tonic-gate MD5Final((unsigned char *)digest->cd_raw.iov_base + 1425*7c478bd9Sstevel@tonic-gate digest->cd_offset, &md5_ctx); 1426*7c478bd9Sstevel@tonic-gate break; 1427*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: 1428*7c478bd9Sstevel@tonic-gate ret = md5_digest_final_uio(&md5_ctx, digest, 1429*7c478bd9Sstevel@tonic-gate MD5_DIGEST_LENGTH, NULL); 1430*7c478bd9Sstevel@tonic-gate break; 1431*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: 1432*7c478bd9Sstevel@tonic-gate ret = md5_digest_final_mblk(&md5_ctx, digest, 1433*7c478bd9Sstevel@tonic-gate MD5_DIGEST_LENGTH, NULL); 1434*7c478bd9Sstevel@tonic-gate break; 1435*7c478bd9Sstevel@tonic-gate default: 1436*7c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; 1437*7c478bd9Sstevel@tonic-gate } 1438*7c478bd9Sstevel@tonic-gate 1439*7c478bd9Sstevel@tonic-gate if (ret == CRYPTO_SUCCESS) { 1440*7c478bd9Sstevel@tonic-gate digest->cd_length = MD5_DIGEST_LENGTH; 1441*7c478bd9Sstevel@tonic-gate } else { 1442*7c478bd9Sstevel@tonic-gate digest->cd_length = 0; 1443*7c478bd9Sstevel@tonic-gate } 1444*7c478bd9Sstevel@tonic-gate 1445*7c478bd9Sstevel@tonic-gate return (ret); 1446*7c478bd9Sstevel@tonic-gate } 1447*7c478bd9Sstevel@tonic-gate 1448*7c478bd9Sstevel@tonic-gate /* 1449*7c478bd9Sstevel@tonic-gate * KCF software provider mac entry points. 1450*7c478bd9Sstevel@tonic-gate * 1451*7c478bd9Sstevel@tonic-gate * MD5 HMAC is: MD5(key XOR opad, MD5(key XOR ipad, text)) 1452*7c478bd9Sstevel@tonic-gate * 1453*7c478bd9Sstevel@tonic-gate * Init: 1454*7c478bd9Sstevel@tonic-gate * The initialization routine initializes what we denote 1455*7c478bd9Sstevel@tonic-gate * as the inner and outer contexts by doing 1456*7c478bd9Sstevel@tonic-gate * - for inner context: MD5(key XOR ipad) 1457*7c478bd9Sstevel@tonic-gate * - for outer context: MD5(key XOR opad) 1458*7c478bd9Sstevel@tonic-gate * 1459*7c478bd9Sstevel@tonic-gate * Update: 1460*7c478bd9Sstevel@tonic-gate * Each subsequent MD5 HMAC update will result in an 1461*7c478bd9Sstevel@tonic-gate * update of the inner context with the specified data. 1462*7c478bd9Sstevel@tonic-gate * 1463*7c478bd9Sstevel@tonic-gate * Final: 1464*7c478bd9Sstevel@tonic-gate * The MD5 HMAC final will do a MD5 final operation on the 1465*7c478bd9Sstevel@tonic-gate * inner context, and the resulting digest will be used 1466*7c478bd9Sstevel@tonic-gate * as the data for an update on the outer context. Last 1467*7c478bd9Sstevel@tonic-gate * but not least, an MD5 final on the outer context will 1468*7c478bd9Sstevel@tonic-gate * be performed to obtain the MD5 HMAC digest to return 1469*7c478bd9Sstevel@tonic-gate * to the user. 1470*7c478bd9Sstevel@tonic-gate */ 1471*7c478bd9Sstevel@tonic-gate 1472*7c478bd9Sstevel@tonic-gate /* 1473*7c478bd9Sstevel@tonic-gate * Initialize a MD5-HMAC context. 1474*7c478bd9Sstevel@tonic-gate */ 1475*7c478bd9Sstevel@tonic-gate static void 1476*7c478bd9Sstevel@tonic-gate md5_mac_init_ctx(md5_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes) 1477*7c478bd9Sstevel@tonic-gate { 1478*7c478bd9Sstevel@tonic-gate uint32_t ipad[MD5_HMAC_INTS_PER_BLOCK]; 1479*7c478bd9Sstevel@tonic-gate uint32_t opad[MD5_HMAC_INTS_PER_BLOCK]; 1480*7c478bd9Sstevel@tonic-gate uint_t i; 1481*7c478bd9Sstevel@tonic-gate 1482*7c478bd9Sstevel@tonic-gate bzero(ipad, MD5_HMAC_BLOCK_SIZE); 1483*7c478bd9Sstevel@tonic-gate bzero(opad, MD5_HMAC_BLOCK_SIZE); 1484*7c478bd9Sstevel@tonic-gate 1485*7c478bd9Sstevel@tonic-gate bcopy(keyval, ipad, length_in_bytes); 1486*7c478bd9Sstevel@tonic-gate bcopy(keyval, opad, length_in_bytes); 1487*7c478bd9Sstevel@tonic-gate 1488*7c478bd9Sstevel@tonic-gate /* XOR key with ipad (0x36) and opad (0x5c) */ 1489*7c478bd9Sstevel@tonic-gate for (i = 0; i < MD5_HMAC_INTS_PER_BLOCK; i++) { 1490*7c478bd9Sstevel@tonic-gate ipad[i] ^= 0x36363636; 1491*7c478bd9Sstevel@tonic-gate opad[i] ^= 0x5c5c5c5c; 1492*7c478bd9Sstevel@tonic-gate } 1493*7c478bd9Sstevel@tonic-gate 1494*7c478bd9Sstevel@tonic-gate /* perform MD5 on ipad */ 1495*7c478bd9Sstevel@tonic-gate MD5Init(&ctx->hc_icontext); 1496*7c478bd9Sstevel@tonic-gate MD5Update(&ctx->hc_icontext, ipad, MD5_HMAC_BLOCK_SIZE); 1497*7c478bd9Sstevel@tonic-gate 1498*7c478bd9Sstevel@tonic-gate /* perform MD5 on opad */ 1499*7c478bd9Sstevel@tonic-gate MD5Init(&ctx->hc_ocontext); 1500*7c478bd9Sstevel@tonic-gate MD5Update(&ctx->hc_ocontext, opad, MD5_HMAC_BLOCK_SIZE); 1501*7c478bd9Sstevel@tonic-gate } 1502*7c478bd9Sstevel@tonic-gate 1503*7c478bd9Sstevel@tonic-gate /* 1504*7c478bd9Sstevel@tonic-gate * Initializes a multi-part MAC operation. 1505*7c478bd9Sstevel@tonic-gate */ 1506*7c478bd9Sstevel@tonic-gate static int 1507*7c478bd9Sstevel@tonic-gate md5_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, 1508*7c478bd9Sstevel@tonic-gate crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, 1509*7c478bd9Sstevel@tonic-gate crypto_req_handle_t req) 1510*7c478bd9Sstevel@tonic-gate { 1511*7c478bd9Sstevel@tonic-gate int ret = CRYPTO_SUCCESS; 1512*7c478bd9Sstevel@tonic-gate uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1513*7c478bd9Sstevel@tonic-gate 1514*7c478bd9Sstevel@tonic-gate if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE && 1515*7c478bd9Sstevel@tonic-gate mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE) 1516*7c478bd9Sstevel@tonic-gate return (CRYPTO_MECHANISM_INVALID); 1517*7c478bd9Sstevel@tonic-gate 1518*7c478bd9Sstevel@tonic-gate /* Add support for key by attributes (RFE 4706552) */ 1519*7c478bd9Sstevel@tonic-gate if (key->ck_format != CRYPTO_KEY_RAW) 1520*7c478bd9Sstevel@tonic-gate return (CRYPTO_ARGUMENTS_BAD); 1521*7c478bd9Sstevel@tonic-gate 1522*7c478bd9Sstevel@tonic-gate ctx->cc_provider_private = kmem_alloc(sizeof (md5_hmac_ctx_t), 1523*7c478bd9Sstevel@tonic-gate crypto_kmflag(req)); 1524*7c478bd9Sstevel@tonic-gate if (ctx->cc_provider_private == NULL) 1525*7c478bd9Sstevel@tonic-gate return (CRYPTO_HOST_MEMORY); 1526*7c478bd9Sstevel@tonic-gate 1527*7c478bd9Sstevel@tonic-gate if (ctx_template != NULL) { 1528*7c478bd9Sstevel@tonic-gate /* reuse context template */ 1529*7c478bd9Sstevel@tonic-gate bcopy(ctx_template, PROV_MD5_HMAC_CTX(ctx), 1530*7c478bd9Sstevel@tonic-gate sizeof (md5_hmac_ctx_t)); 1531*7c478bd9Sstevel@tonic-gate } else { 1532*7c478bd9Sstevel@tonic-gate /* no context template, compute context */ 1533*7c478bd9Sstevel@tonic-gate if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 1534*7c478bd9Sstevel@tonic-gate uchar_t digested_key[MD5_DIGEST_LENGTH]; 1535*7c478bd9Sstevel@tonic-gate md5_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private; 1536*7c478bd9Sstevel@tonic-gate 1537*7c478bd9Sstevel@tonic-gate /* 1538*7c478bd9Sstevel@tonic-gate * Hash the passed-in key to get a smaller key. 1539*7c478bd9Sstevel@tonic-gate * The inner context is used since it hasn't been 1540*7c478bd9Sstevel@tonic-gate * initialized yet. 1541*7c478bd9Sstevel@tonic-gate */ 1542*7c478bd9Sstevel@tonic-gate PROV_MD5_DIGEST_KEY(&hmac_ctx->hc_icontext, 1543*7c478bd9Sstevel@tonic-gate key->ck_data, keylen_in_bytes, digested_key); 1544*7c478bd9Sstevel@tonic-gate md5_mac_init_ctx(PROV_MD5_HMAC_CTX(ctx), 1545*7c478bd9Sstevel@tonic-gate digested_key, MD5_DIGEST_LENGTH); 1546*7c478bd9Sstevel@tonic-gate } else { 1547*7c478bd9Sstevel@tonic-gate md5_mac_init_ctx(PROV_MD5_HMAC_CTX(ctx), 1548*7c478bd9Sstevel@tonic-gate key->ck_data, keylen_in_bytes); 1549*7c478bd9Sstevel@tonic-gate } 1550*7c478bd9Sstevel@tonic-gate } 1551*7c478bd9Sstevel@tonic-gate 1552*7c478bd9Sstevel@tonic-gate /* 1553*7c478bd9Sstevel@tonic-gate * Get the mechanism parameters, if applicable. 1554*7c478bd9Sstevel@tonic-gate */ 1555*7c478bd9Sstevel@tonic-gate PROV_MD5_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type; 1556*7c478bd9Sstevel@tonic-gate if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) { 1557*7c478bd9Sstevel@tonic-gate if (mechanism->cm_param == NULL || 1558*7c478bd9Sstevel@tonic-gate mechanism->cm_param_len != sizeof (ulong_t)) 1559*7c478bd9Sstevel@tonic-gate ret = CRYPTO_MECHANISM_PARAM_INVALID; 1560*7c478bd9Sstevel@tonic-gate PROV_MD5_GET_DIGEST_LEN(mechanism, 1561*7c478bd9Sstevel@tonic-gate PROV_MD5_HMAC_CTX(ctx)->hc_digest_len); 1562*7c478bd9Sstevel@tonic-gate if (PROV_MD5_HMAC_CTX(ctx)->hc_digest_len > 1563*7c478bd9Sstevel@tonic-gate MD5_DIGEST_LENGTH) 1564*7c478bd9Sstevel@tonic-gate ret = CRYPTO_MECHANISM_PARAM_INVALID; 1565*7c478bd9Sstevel@tonic-gate } 1566*7c478bd9Sstevel@tonic-gate 1567*7c478bd9Sstevel@tonic-gate if (ret != CRYPTO_SUCCESS) { 1568*7c478bd9Sstevel@tonic-gate bzero(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 1569*7c478bd9Sstevel@tonic-gate kmem_free(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 1570*7c478bd9Sstevel@tonic-gate ctx->cc_provider_private = NULL; 1571*7c478bd9Sstevel@tonic-gate } 1572*7c478bd9Sstevel@tonic-gate 1573*7c478bd9Sstevel@tonic-gate return (ret); 1574*7c478bd9Sstevel@tonic-gate } 1575*7c478bd9Sstevel@tonic-gate 1576*7c478bd9Sstevel@tonic-gate 1577*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1578*7c478bd9Sstevel@tonic-gate static int 1579*7c478bd9Sstevel@tonic-gate md5_mac_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req) 1580*7c478bd9Sstevel@tonic-gate { 1581*7c478bd9Sstevel@tonic-gate int ret = CRYPTO_SUCCESS; 1582*7c478bd9Sstevel@tonic-gate 1583*7c478bd9Sstevel@tonic-gate ASSERT(ctx->cc_provider_private != NULL); 1584*7c478bd9Sstevel@tonic-gate 1585*7c478bd9Sstevel@tonic-gate /* 1586*7c478bd9Sstevel@tonic-gate * Do an MD5 update of the inner context using the specified 1587*7c478bd9Sstevel@tonic-gate * data. 1588*7c478bd9Sstevel@tonic-gate */ 1589*7c478bd9Sstevel@tonic-gate switch (data->cd_format) { 1590*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: 1591*7c478bd9Sstevel@tonic-gate MD5Update(&PROV_MD5_HMAC_CTX(ctx)->hc_icontext, 1592*7c478bd9Sstevel@tonic-gate data->cd_raw.iov_base + data->cd_offset, 1593*7c478bd9Sstevel@tonic-gate data->cd_length); 1594*7c478bd9Sstevel@tonic-gate break; 1595*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: 1596*7c478bd9Sstevel@tonic-gate ret = md5_digest_update_uio( 1597*7c478bd9Sstevel@tonic-gate &PROV_MD5_HMAC_CTX(ctx)->hc_icontext, data); 1598*7c478bd9Sstevel@tonic-gate break; 1599*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: 1600*7c478bd9Sstevel@tonic-gate ret = md5_digest_update_mblk( 1601*7c478bd9Sstevel@tonic-gate &PROV_MD5_HMAC_CTX(ctx)->hc_icontext, data); 1602*7c478bd9Sstevel@tonic-gate break; 1603*7c478bd9Sstevel@tonic-gate default: 1604*7c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; 1605*7c478bd9Sstevel@tonic-gate } 1606*7c478bd9Sstevel@tonic-gate 1607*7c478bd9Sstevel@tonic-gate return (ret); 1608*7c478bd9Sstevel@tonic-gate } 1609*7c478bd9Sstevel@tonic-gate 1610*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1611*7c478bd9Sstevel@tonic-gate static int 1612*7c478bd9Sstevel@tonic-gate md5_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req) 1613*7c478bd9Sstevel@tonic-gate { 1614*7c478bd9Sstevel@tonic-gate int ret = CRYPTO_SUCCESS; 1615*7c478bd9Sstevel@tonic-gate uchar_t digest[MD5_DIGEST_LENGTH]; 1616*7c478bd9Sstevel@tonic-gate uint32_t digest_len = MD5_DIGEST_LENGTH; 1617*7c478bd9Sstevel@tonic-gate 1618*7c478bd9Sstevel@tonic-gate ASSERT(ctx->cc_provider_private != NULL); 1619*7c478bd9Sstevel@tonic-gate 1620*7c478bd9Sstevel@tonic-gate if (PROV_MD5_HMAC_CTX(ctx)->hc_mech_type == MD5_HMAC_GEN_MECH_INFO_TYPE) 1621*7c478bd9Sstevel@tonic-gate digest_len = PROV_MD5_HMAC_CTX(ctx)->hc_digest_len; 1622*7c478bd9Sstevel@tonic-gate 1623*7c478bd9Sstevel@tonic-gate /* 1624*7c478bd9Sstevel@tonic-gate * We need to just return the length needed to store the output. 1625*7c478bd9Sstevel@tonic-gate * We should not destroy the context for the following cases. 1626*7c478bd9Sstevel@tonic-gate */ 1627*7c478bd9Sstevel@tonic-gate if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) { 1628*7c478bd9Sstevel@tonic-gate mac->cd_length = digest_len; 1629*7c478bd9Sstevel@tonic-gate return (CRYPTO_BUFFER_TOO_SMALL); 1630*7c478bd9Sstevel@tonic-gate } 1631*7c478bd9Sstevel@tonic-gate 1632*7c478bd9Sstevel@tonic-gate /* 1633*7c478bd9Sstevel@tonic-gate * Do an MD5 final on the inner context. 1634*7c478bd9Sstevel@tonic-gate */ 1635*7c478bd9Sstevel@tonic-gate MD5Final(digest, &PROV_MD5_HMAC_CTX(ctx)->hc_icontext); 1636*7c478bd9Sstevel@tonic-gate 1637*7c478bd9Sstevel@tonic-gate /* 1638*7c478bd9Sstevel@tonic-gate * Do an MD5 update on the outer context, feeding the inner 1639*7c478bd9Sstevel@tonic-gate * digest as data. 1640*7c478bd9Sstevel@tonic-gate */ 1641*7c478bd9Sstevel@tonic-gate MD5Update(&PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, digest, 1642*7c478bd9Sstevel@tonic-gate MD5_DIGEST_LENGTH); 1643*7c478bd9Sstevel@tonic-gate 1644*7c478bd9Sstevel@tonic-gate /* 1645*7c478bd9Sstevel@tonic-gate * Do an MD5 final on the outer context, storing the computing 1646*7c478bd9Sstevel@tonic-gate * digest in the users buffer. 1647*7c478bd9Sstevel@tonic-gate */ 1648*7c478bd9Sstevel@tonic-gate switch (mac->cd_format) { 1649*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: 1650*7c478bd9Sstevel@tonic-gate if (digest_len != MD5_DIGEST_LENGTH) { 1651*7c478bd9Sstevel@tonic-gate /* 1652*7c478bd9Sstevel@tonic-gate * The caller requested a short digest. Digest 1653*7c478bd9Sstevel@tonic-gate * into a scratch buffer and return to 1654*7c478bd9Sstevel@tonic-gate * the user only what was requested. 1655*7c478bd9Sstevel@tonic-gate */ 1656*7c478bd9Sstevel@tonic-gate MD5Final(digest, 1657*7c478bd9Sstevel@tonic-gate &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext); 1658*7c478bd9Sstevel@tonic-gate bcopy(digest, (unsigned char *)mac->cd_raw.iov_base + 1659*7c478bd9Sstevel@tonic-gate mac->cd_offset, digest_len); 1660*7c478bd9Sstevel@tonic-gate } else { 1661*7c478bd9Sstevel@tonic-gate MD5Final((unsigned char *)mac->cd_raw.iov_base + 1662*7c478bd9Sstevel@tonic-gate mac->cd_offset, 1663*7c478bd9Sstevel@tonic-gate &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext); 1664*7c478bd9Sstevel@tonic-gate } 1665*7c478bd9Sstevel@tonic-gate break; 1666*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: 1667*7c478bd9Sstevel@tonic-gate ret = md5_digest_final_uio( 1668*7c478bd9Sstevel@tonic-gate &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, mac, 1669*7c478bd9Sstevel@tonic-gate digest_len, digest); 1670*7c478bd9Sstevel@tonic-gate break; 1671*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: 1672*7c478bd9Sstevel@tonic-gate ret = md5_digest_final_mblk( 1673*7c478bd9Sstevel@tonic-gate &PROV_MD5_HMAC_CTX(ctx)->hc_ocontext, mac, 1674*7c478bd9Sstevel@tonic-gate digest_len, digest); 1675*7c478bd9Sstevel@tonic-gate break; 1676*7c478bd9Sstevel@tonic-gate default: 1677*7c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; 1678*7c478bd9Sstevel@tonic-gate } 1679*7c478bd9Sstevel@tonic-gate 1680*7c478bd9Sstevel@tonic-gate if (ret == CRYPTO_SUCCESS) { 1681*7c478bd9Sstevel@tonic-gate mac->cd_length = digest_len; 1682*7c478bd9Sstevel@tonic-gate } else { 1683*7c478bd9Sstevel@tonic-gate mac->cd_length = 0; 1684*7c478bd9Sstevel@tonic-gate } 1685*7c478bd9Sstevel@tonic-gate 1686*7c478bd9Sstevel@tonic-gate bzero(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 1687*7c478bd9Sstevel@tonic-gate kmem_free(ctx->cc_provider_private, sizeof (md5_hmac_ctx_t)); 1688*7c478bd9Sstevel@tonic-gate ctx->cc_provider_private = NULL; 1689*7c478bd9Sstevel@tonic-gate 1690*7c478bd9Sstevel@tonic-gate return (ret); 1691*7c478bd9Sstevel@tonic-gate } 1692*7c478bd9Sstevel@tonic-gate 1693*7c478bd9Sstevel@tonic-gate #define MD5_MAC_UPDATE(data, ctx, ret) { \ 1694*7c478bd9Sstevel@tonic-gate switch (data->cd_format) { \ 1695*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: \ 1696*7c478bd9Sstevel@tonic-gate MD5Update(&(ctx).hc_icontext, \ 1697*7c478bd9Sstevel@tonic-gate data->cd_raw.iov_base + data->cd_offset, \ 1698*7c478bd9Sstevel@tonic-gate data->cd_length); \ 1699*7c478bd9Sstevel@tonic-gate break; \ 1700*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: \ 1701*7c478bd9Sstevel@tonic-gate ret = md5_digest_update_uio(&(ctx).hc_icontext, data); \ 1702*7c478bd9Sstevel@tonic-gate break; \ 1703*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: \ 1704*7c478bd9Sstevel@tonic-gate ret = md5_digest_update_mblk(&(ctx).hc_icontext, \ 1705*7c478bd9Sstevel@tonic-gate data); \ 1706*7c478bd9Sstevel@tonic-gate break; \ 1707*7c478bd9Sstevel@tonic-gate default: \ 1708*7c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; \ 1709*7c478bd9Sstevel@tonic-gate } \ 1710*7c478bd9Sstevel@tonic-gate } 1711*7c478bd9Sstevel@tonic-gate 1712*7c478bd9Sstevel@tonic-gate 1713*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1714*7c478bd9Sstevel@tonic-gate static int 1715*7c478bd9Sstevel@tonic-gate md5_mac_atomic(crypto_provider_handle_t provider, 1716*7c478bd9Sstevel@tonic-gate crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 1717*7c478bd9Sstevel@tonic-gate crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, 1718*7c478bd9Sstevel@tonic-gate crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 1719*7c478bd9Sstevel@tonic-gate { 1720*7c478bd9Sstevel@tonic-gate int ret = CRYPTO_SUCCESS; 1721*7c478bd9Sstevel@tonic-gate uchar_t digest[MD5_DIGEST_LENGTH]; 1722*7c478bd9Sstevel@tonic-gate md5_hmac_ctx_t md5_hmac_ctx; 1723*7c478bd9Sstevel@tonic-gate uint32_t digest_len = MD5_DIGEST_LENGTH; 1724*7c478bd9Sstevel@tonic-gate uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1725*7c478bd9Sstevel@tonic-gate 1726*7c478bd9Sstevel@tonic-gate if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE && 1727*7c478bd9Sstevel@tonic-gate mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE) 1728*7c478bd9Sstevel@tonic-gate return (CRYPTO_MECHANISM_INVALID); 1729*7c478bd9Sstevel@tonic-gate 1730*7c478bd9Sstevel@tonic-gate /* Add support for key by attributes (RFE 4706552) */ 1731*7c478bd9Sstevel@tonic-gate if (key->ck_format != CRYPTO_KEY_RAW) 1732*7c478bd9Sstevel@tonic-gate return (CRYPTO_ARGUMENTS_BAD); 1733*7c478bd9Sstevel@tonic-gate 1734*7c478bd9Sstevel@tonic-gate if (ctx_template != NULL) { 1735*7c478bd9Sstevel@tonic-gate /* reuse context template */ 1736*7c478bd9Sstevel@tonic-gate bcopy(ctx_template, &md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1737*7c478bd9Sstevel@tonic-gate } else { 1738*7c478bd9Sstevel@tonic-gate /* no context template, compute context */ 1739*7c478bd9Sstevel@tonic-gate if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 1740*7c478bd9Sstevel@tonic-gate /* 1741*7c478bd9Sstevel@tonic-gate * Hash the passed-in key to get a smaller key. 1742*7c478bd9Sstevel@tonic-gate * The inner context is used since it hasn't been 1743*7c478bd9Sstevel@tonic-gate * initialized yet. 1744*7c478bd9Sstevel@tonic-gate */ 1745*7c478bd9Sstevel@tonic-gate PROV_MD5_DIGEST_KEY(&md5_hmac_ctx.hc_icontext, 1746*7c478bd9Sstevel@tonic-gate key->ck_data, keylen_in_bytes, digest); 1747*7c478bd9Sstevel@tonic-gate md5_mac_init_ctx(&md5_hmac_ctx, digest, 1748*7c478bd9Sstevel@tonic-gate MD5_DIGEST_LENGTH); 1749*7c478bd9Sstevel@tonic-gate } else { 1750*7c478bd9Sstevel@tonic-gate md5_mac_init_ctx(&md5_hmac_ctx, key->ck_data, 1751*7c478bd9Sstevel@tonic-gate keylen_in_bytes); 1752*7c478bd9Sstevel@tonic-gate } 1753*7c478bd9Sstevel@tonic-gate } 1754*7c478bd9Sstevel@tonic-gate 1755*7c478bd9Sstevel@tonic-gate /* 1756*7c478bd9Sstevel@tonic-gate * Get the mechanism parameters, if applicable. 1757*7c478bd9Sstevel@tonic-gate */ 1758*7c478bd9Sstevel@tonic-gate if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) { 1759*7c478bd9Sstevel@tonic-gate if (mechanism->cm_param == NULL || 1760*7c478bd9Sstevel@tonic-gate mechanism->cm_param_len != sizeof (ulong_t)) { 1761*7c478bd9Sstevel@tonic-gate ret = CRYPTO_MECHANISM_PARAM_INVALID; 1762*7c478bd9Sstevel@tonic-gate goto bail; 1763*7c478bd9Sstevel@tonic-gate } 1764*7c478bd9Sstevel@tonic-gate PROV_MD5_GET_DIGEST_LEN(mechanism, digest_len); 1765*7c478bd9Sstevel@tonic-gate if (digest_len > MD5_DIGEST_LENGTH) { 1766*7c478bd9Sstevel@tonic-gate ret = CRYPTO_MECHANISM_PARAM_INVALID; 1767*7c478bd9Sstevel@tonic-gate goto bail; 1768*7c478bd9Sstevel@tonic-gate } 1769*7c478bd9Sstevel@tonic-gate } 1770*7c478bd9Sstevel@tonic-gate 1771*7c478bd9Sstevel@tonic-gate /* do an MD5 update of the inner context using the specified data */ 1772*7c478bd9Sstevel@tonic-gate MD5_MAC_UPDATE(data, md5_hmac_ctx, ret); 1773*7c478bd9Sstevel@tonic-gate if (ret != CRYPTO_SUCCESS) 1774*7c478bd9Sstevel@tonic-gate /* the update failed, free context and bail */ 1775*7c478bd9Sstevel@tonic-gate goto bail; 1776*7c478bd9Sstevel@tonic-gate 1777*7c478bd9Sstevel@tonic-gate /* do an MD5 final on the inner context */ 1778*7c478bd9Sstevel@tonic-gate MD5Final(digest, &md5_hmac_ctx.hc_icontext); 1779*7c478bd9Sstevel@tonic-gate 1780*7c478bd9Sstevel@tonic-gate /* 1781*7c478bd9Sstevel@tonic-gate * Do an MD5 update on the outer context, feeding the inner 1782*7c478bd9Sstevel@tonic-gate * digest as data. 1783*7c478bd9Sstevel@tonic-gate */ 1784*7c478bd9Sstevel@tonic-gate MD5Update(&md5_hmac_ctx.hc_ocontext, digest, MD5_DIGEST_LENGTH); 1785*7c478bd9Sstevel@tonic-gate 1786*7c478bd9Sstevel@tonic-gate /* 1787*7c478bd9Sstevel@tonic-gate * Do an MD5 final on the outer context, storing the computed 1788*7c478bd9Sstevel@tonic-gate * digest in the users buffer. 1789*7c478bd9Sstevel@tonic-gate */ 1790*7c478bd9Sstevel@tonic-gate switch (mac->cd_format) { 1791*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: 1792*7c478bd9Sstevel@tonic-gate if (digest_len != MD5_DIGEST_LENGTH) { 1793*7c478bd9Sstevel@tonic-gate /* 1794*7c478bd9Sstevel@tonic-gate * The caller requested a short digest. Digest 1795*7c478bd9Sstevel@tonic-gate * into a scratch buffer and return to 1796*7c478bd9Sstevel@tonic-gate * the user only what was requested. 1797*7c478bd9Sstevel@tonic-gate */ 1798*7c478bd9Sstevel@tonic-gate MD5Final(digest, &md5_hmac_ctx.hc_ocontext); 1799*7c478bd9Sstevel@tonic-gate bcopy(digest, (unsigned char *)mac->cd_raw.iov_base + 1800*7c478bd9Sstevel@tonic-gate mac->cd_offset, digest_len); 1801*7c478bd9Sstevel@tonic-gate } else { 1802*7c478bd9Sstevel@tonic-gate MD5Final((unsigned char *)mac->cd_raw.iov_base + 1803*7c478bd9Sstevel@tonic-gate mac->cd_offset, &md5_hmac_ctx.hc_ocontext); 1804*7c478bd9Sstevel@tonic-gate } 1805*7c478bd9Sstevel@tonic-gate break; 1806*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: 1807*7c478bd9Sstevel@tonic-gate ret = md5_digest_final_uio(&md5_hmac_ctx.hc_ocontext, mac, 1808*7c478bd9Sstevel@tonic-gate digest_len, digest); 1809*7c478bd9Sstevel@tonic-gate break; 1810*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: 1811*7c478bd9Sstevel@tonic-gate ret = md5_digest_final_mblk(&md5_hmac_ctx.hc_ocontext, mac, 1812*7c478bd9Sstevel@tonic-gate digest_len, digest); 1813*7c478bd9Sstevel@tonic-gate break; 1814*7c478bd9Sstevel@tonic-gate default: 1815*7c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; 1816*7c478bd9Sstevel@tonic-gate } 1817*7c478bd9Sstevel@tonic-gate 1818*7c478bd9Sstevel@tonic-gate if (ret == CRYPTO_SUCCESS) { 1819*7c478bd9Sstevel@tonic-gate mac->cd_length = digest_len; 1820*7c478bd9Sstevel@tonic-gate } else { 1821*7c478bd9Sstevel@tonic-gate mac->cd_length = 0; 1822*7c478bd9Sstevel@tonic-gate } 1823*7c478bd9Sstevel@tonic-gate /* Extra paranoia: zeroizing the local context on the stack */ 1824*7c478bd9Sstevel@tonic-gate bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1825*7c478bd9Sstevel@tonic-gate 1826*7c478bd9Sstevel@tonic-gate return (ret); 1827*7c478bd9Sstevel@tonic-gate bail: 1828*7c478bd9Sstevel@tonic-gate bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1829*7c478bd9Sstevel@tonic-gate mac->cd_length = 0; 1830*7c478bd9Sstevel@tonic-gate return (ret); 1831*7c478bd9Sstevel@tonic-gate } 1832*7c478bd9Sstevel@tonic-gate 1833*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1834*7c478bd9Sstevel@tonic-gate static int 1835*7c478bd9Sstevel@tonic-gate md5_mac_verify_atomic(crypto_provider_handle_t provider, 1836*7c478bd9Sstevel@tonic-gate crypto_session_id_t session_id, crypto_mechanism_t *mechanism, 1837*7c478bd9Sstevel@tonic-gate crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, 1838*7c478bd9Sstevel@tonic-gate crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) 1839*7c478bd9Sstevel@tonic-gate { 1840*7c478bd9Sstevel@tonic-gate int ret = CRYPTO_SUCCESS; 1841*7c478bd9Sstevel@tonic-gate uchar_t digest[MD5_DIGEST_LENGTH]; 1842*7c478bd9Sstevel@tonic-gate md5_hmac_ctx_t md5_hmac_ctx; 1843*7c478bd9Sstevel@tonic-gate uint32_t digest_len = MD5_DIGEST_LENGTH; 1844*7c478bd9Sstevel@tonic-gate uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 1845*7c478bd9Sstevel@tonic-gate 1846*7c478bd9Sstevel@tonic-gate if (mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE && 1847*7c478bd9Sstevel@tonic-gate mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE) 1848*7c478bd9Sstevel@tonic-gate return (CRYPTO_MECHANISM_INVALID); 1849*7c478bd9Sstevel@tonic-gate 1850*7c478bd9Sstevel@tonic-gate /* Add support for key by attributes (RFE 4706552) */ 1851*7c478bd9Sstevel@tonic-gate if (key->ck_format != CRYPTO_KEY_RAW) 1852*7c478bd9Sstevel@tonic-gate return (CRYPTO_ARGUMENTS_BAD); 1853*7c478bd9Sstevel@tonic-gate 1854*7c478bd9Sstevel@tonic-gate if (ctx_template != NULL) { 1855*7c478bd9Sstevel@tonic-gate /* reuse context template */ 1856*7c478bd9Sstevel@tonic-gate bcopy(ctx_template, &md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 1857*7c478bd9Sstevel@tonic-gate } else { 1858*7c478bd9Sstevel@tonic-gate /* no context template, compute context */ 1859*7c478bd9Sstevel@tonic-gate if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 1860*7c478bd9Sstevel@tonic-gate /* 1861*7c478bd9Sstevel@tonic-gate * Hash the passed-in key to get a smaller key. 1862*7c478bd9Sstevel@tonic-gate * The inner context is used since it hasn't been 1863*7c478bd9Sstevel@tonic-gate * initialized yet. 1864*7c478bd9Sstevel@tonic-gate */ 1865*7c478bd9Sstevel@tonic-gate PROV_MD5_DIGEST_KEY(&md5_hmac_ctx.hc_icontext, 1866*7c478bd9Sstevel@tonic-gate key->ck_data, keylen_in_bytes, digest); 1867*7c478bd9Sstevel@tonic-gate md5_mac_init_ctx(&md5_hmac_ctx, digest, 1868*7c478bd9Sstevel@tonic-gate MD5_DIGEST_LENGTH); 1869*7c478bd9Sstevel@tonic-gate } else { 1870*7c478bd9Sstevel@tonic-gate md5_mac_init_ctx(&md5_hmac_ctx, key->ck_data, 1871*7c478bd9Sstevel@tonic-gate keylen_in_bytes); 1872*7c478bd9Sstevel@tonic-gate } 1873*7c478bd9Sstevel@tonic-gate } 1874*7c478bd9Sstevel@tonic-gate 1875*7c478bd9Sstevel@tonic-gate /* 1876*7c478bd9Sstevel@tonic-gate * Get the mechanism parameters, if applicable. 1877*7c478bd9Sstevel@tonic-gate */ 1878*7c478bd9Sstevel@tonic-gate if (mechanism->cm_type == MD5_HMAC_GEN_MECH_INFO_TYPE) { 1879*7c478bd9Sstevel@tonic-gate if (mechanism->cm_param == NULL || 1880*7c478bd9Sstevel@tonic-gate mechanism->cm_param_len != sizeof (ulong_t)) { 1881*7c478bd9Sstevel@tonic-gate ret = CRYPTO_MECHANISM_PARAM_INVALID; 1882*7c478bd9Sstevel@tonic-gate goto bail; 1883*7c478bd9Sstevel@tonic-gate } 1884*7c478bd9Sstevel@tonic-gate PROV_MD5_GET_DIGEST_LEN(mechanism, digest_len); 1885*7c478bd9Sstevel@tonic-gate if (digest_len > MD5_DIGEST_LENGTH) { 1886*7c478bd9Sstevel@tonic-gate ret = CRYPTO_MECHANISM_PARAM_INVALID; 1887*7c478bd9Sstevel@tonic-gate goto bail; 1888*7c478bd9Sstevel@tonic-gate } 1889*7c478bd9Sstevel@tonic-gate } 1890*7c478bd9Sstevel@tonic-gate 1891*7c478bd9Sstevel@tonic-gate if (mac->cd_length != digest_len) { 1892*7c478bd9Sstevel@tonic-gate ret = CRYPTO_INVALID_MAC; 1893*7c478bd9Sstevel@tonic-gate goto bail; 1894*7c478bd9Sstevel@tonic-gate } 1895*7c478bd9Sstevel@tonic-gate 1896*7c478bd9Sstevel@tonic-gate /* do an MD5 update of the inner context using the specified data */ 1897*7c478bd9Sstevel@tonic-gate MD5_MAC_UPDATE(data, md5_hmac_ctx, ret); 1898*7c478bd9Sstevel@tonic-gate if (ret != CRYPTO_SUCCESS) 1899*7c478bd9Sstevel@tonic-gate /* the update failed, free context and bail */ 1900*7c478bd9Sstevel@tonic-gate goto bail; 1901*7c478bd9Sstevel@tonic-gate 1902*7c478bd9Sstevel@tonic-gate /* do an MD5 final on the inner context */ 1903*7c478bd9Sstevel@tonic-gate MD5Final(digest, &md5_hmac_ctx.hc_icontext); 1904*7c478bd9Sstevel@tonic-gate 1905*7c478bd9Sstevel@tonic-gate /* 1906*7c478bd9Sstevel@tonic-gate * Do an MD5 update on the outer context, feeding the inner 1907*7c478bd9Sstevel@tonic-gate * digest as data. 1908*7c478bd9Sstevel@tonic-gate */ 1909*7c478bd9Sstevel@tonic-gate MD5Update(&md5_hmac_ctx.hc_ocontext, digest, MD5_DIGEST_LENGTH); 1910*7c478bd9Sstevel@tonic-gate 1911*7c478bd9Sstevel@tonic-gate /* 1912*7c478bd9Sstevel@tonic-gate * Do an MD5 final on the outer context, storing the computed 1913*7c478bd9Sstevel@tonic-gate * digest in the local digest buffer. 1914*7c478bd9Sstevel@tonic-gate */ 1915*7c478bd9Sstevel@tonic-gate MD5Final(digest, &md5_hmac_ctx.hc_ocontext); 1916*7c478bd9Sstevel@tonic-gate 1917*7c478bd9Sstevel@tonic-gate /* 1918*7c478bd9Sstevel@tonic-gate * Compare the computed digest against the expected digest passed 1919*7c478bd9Sstevel@tonic-gate * as argument. 1920*7c478bd9Sstevel@tonic-gate */ 1921*7c478bd9Sstevel@tonic-gate switch (mac->cd_format) { 1922*7c478bd9Sstevel@tonic-gate 1923*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_RAW: 1924*7c478bd9Sstevel@tonic-gate if (bcmp(digest, (unsigned char *)mac->cd_raw.iov_base + 1925*7c478bd9Sstevel@tonic-gate mac->cd_offset, digest_len) != 0) 1926*7c478bd9Sstevel@tonic-gate ret = CRYPTO_INVALID_MAC; 1927*7c478bd9Sstevel@tonic-gate break; 1928*7c478bd9Sstevel@tonic-gate 1929*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_UIO: { 1930*7c478bd9Sstevel@tonic-gate off_t offset = mac->cd_offset; 1931*7c478bd9Sstevel@tonic-gate uint_t vec_idx; 1932*7c478bd9Sstevel@tonic-gate off_t scratch_offset = 0; 1933*7c478bd9Sstevel@tonic-gate size_t length = digest_len; 1934*7c478bd9Sstevel@tonic-gate size_t cur_len; 1935*7c478bd9Sstevel@tonic-gate 1936*7c478bd9Sstevel@tonic-gate /* we support only kernel buffer */ 1937*7c478bd9Sstevel@tonic-gate if (mac->cd_uio->uio_segflg != UIO_SYSSPACE) 1938*7c478bd9Sstevel@tonic-gate return (CRYPTO_ARGUMENTS_BAD); 1939*7c478bd9Sstevel@tonic-gate 1940*7c478bd9Sstevel@tonic-gate /* jump to the first iovec containing the expected digest */ 1941*7c478bd9Sstevel@tonic-gate for (vec_idx = 0; 1942*7c478bd9Sstevel@tonic-gate offset >= mac->cd_uio->uio_iov[vec_idx].iov_len && 1943*7c478bd9Sstevel@tonic-gate vec_idx < mac->cd_uio->uio_iovcnt; 1944*7c478bd9Sstevel@tonic-gate offset -= mac->cd_uio->uio_iov[vec_idx++].iov_len); 1945*7c478bd9Sstevel@tonic-gate if (vec_idx == mac->cd_uio->uio_iovcnt) { 1946*7c478bd9Sstevel@tonic-gate /* 1947*7c478bd9Sstevel@tonic-gate * The caller specified an offset that is 1948*7c478bd9Sstevel@tonic-gate * larger than the total size of the buffers 1949*7c478bd9Sstevel@tonic-gate * it provided. 1950*7c478bd9Sstevel@tonic-gate */ 1951*7c478bd9Sstevel@tonic-gate ret = CRYPTO_DATA_LEN_RANGE; 1952*7c478bd9Sstevel@tonic-gate break; 1953*7c478bd9Sstevel@tonic-gate } 1954*7c478bd9Sstevel@tonic-gate 1955*7c478bd9Sstevel@tonic-gate /* do the comparison of computed digest vs specified one */ 1956*7c478bd9Sstevel@tonic-gate while (vec_idx < mac->cd_uio->uio_iovcnt && length > 0) { 1957*7c478bd9Sstevel@tonic-gate cur_len = MIN(mac->cd_uio->uio_iov[vec_idx].iov_len - 1958*7c478bd9Sstevel@tonic-gate offset, length); 1959*7c478bd9Sstevel@tonic-gate 1960*7c478bd9Sstevel@tonic-gate if (bcmp(digest + scratch_offset, 1961*7c478bd9Sstevel@tonic-gate mac->cd_uio->uio_iov[vec_idx].iov_base + offset, 1962*7c478bd9Sstevel@tonic-gate cur_len) != 0) { 1963*7c478bd9Sstevel@tonic-gate ret = CRYPTO_INVALID_MAC; 1964*7c478bd9Sstevel@tonic-gate break; 1965*7c478bd9Sstevel@tonic-gate } 1966*7c478bd9Sstevel@tonic-gate 1967*7c478bd9Sstevel@tonic-gate length -= cur_len; 1968*7c478bd9Sstevel@tonic-gate vec_idx++; 1969*7c478bd9Sstevel@tonic-gate scratch_offset += cur_len; 1970*7c478bd9Sstevel@tonic-gate offset = 0; 1971*7c478bd9Sstevel@tonic-gate } 1972*7c478bd9Sstevel@tonic-gate break; 1973*7c478bd9Sstevel@tonic-gate } 1974*7c478bd9Sstevel@tonic-gate 1975*7c478bd9Sstevel@tonic-gate case CRYPTO_DATA_MBLK: { 1976*7c478bd9Sstevel@tonic-gate off_t offset = mac->cd_offset; 1977*7c478bd9Sstevel@tonic-gate mblk_t *mp; 1978*7c478bd9Sstevel@tonic-gate off_t scratch_offset = 0; 1979*7c478bd9Sstevel@tonic-gate size_t length = digest_len; 1980*7c478bd9Sstevel@tonic-gate size_t cur_len; 1981*7c478bd9Sstevel@tonic-gate 1982*7c478bd9Sstevel@tonic-gate /* jump to the first mblk_t containing the expected digest */ 1983*7c478bd9Sstevel@tonic-gate for (mp = mac->cd_mp; mp != NULL && offset >= MBLKL(mp); 1984*7c478bd9Sstevel@tonic-gate offset -= MBLKL(mp), mp = mp->b_cont); 1985*7c478bd9Sstevel@tonic-gate if (mp == NULL) { 1986*7c478bd9Sstevel@tonic-gate /* 1987*7c478bd9Sstevel@tonic-gate * The caller specified an offset that is larger than 1988*7c478bd9Sstevel@tonic-gate * the total size of the buffers it provided. 1989*7c478bd9Sstevel@tonic-gate */ 1990*7c478bd9Sstevel@tonic-gate ret = CRYPTO_DATA_LEN_RANGE; 1991*7c478bd9Sstevel@tonic-gate break; 1992*7c478bd9Sstevel@tonic-gate } 1993*7c478bd9Sstevel@tonic-gate 1994*7c478bd9Sstevel@tonic-gate while (mp != NULL && length > 0) { 1995*7c478bd9Sstevel@tonic-gate cur_len = MIN(MBLKL(mp) - offset, length); 1996*7c478bd9Sstevel@tonic-gate if (bcmp(digest + scratch_offset, 1997*7c478bd9Sstevel@tonic-gate mp->b_rptr + offset, cur_len) != 0) { 1998*7c478bd9Sstevel@tonic-gate ret = CRYPTO_INVALID_MAC; 1999*7c478bd9Sstevel@tonic-gate break; 2000*7c478bd9Sstevel@tonic-gate } 2001*7c478bd9Sstevel@tonic-gate 2002*7c478bd9Sstevel@tonic-gate length -= cur_len; 2003*7c478bd9Sstevel@tonic-gate mp = mp->b_cont; 2004*7c478bd9Sstevel@tonic-gate scratch_offset += cur_len; 2005*7c478bd9Sstevel@tonic-gate offset = 0; 2006*7c478bd9Sstevel@tonic-gate } 2007*7c478bd9Sstevel@tonic-gate break; 2008*7c478bd9Sstevel@tonic-gate } 2009*7c478bd9Sstevel@tonic-gate 2010*7c478bd9Sstevel@tonic-gate default: 2011*7c478bd9Sstevel@tonic-gate ret = CRYPTO_ARGUMENTS_BAD; 2012*7c478bd9Sstevel@tonic-gate } 2013*7c478bd9Sstevel@tonic-gate 2014*7c478bd9Sstevel@tonic-gate bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 2015*7c478bd9Sstevel@tonic-gate return (ret); 2016*7c478bd9Sstevel@tonic-gate bail: 2017*7c478bd9Sstevel@tonic-gate bzero(&md5_hmac_ctx, sizeof (md5_hmac_ctx_t)); 2018*7c478bd9Sstevel@tonic-gate mac->cd_length = 0; 2019*7c478bd9Sstevel@tonic-gate return (ret); 2020*7c478bd9Sstevel@tonic-gate } 2021*7c478bd9Sstevel@tonic-gate 2022*7c478bd9Sstevel@tonic-gate /* 2023*7c478bd9Sstevel@tonic-gate * KCF software provider context management entry points. 2024*7c478bd9Sstevel@tonic-gate */ 2025*7c478bd9Sstevel@tonic-gate 2026*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2027*7c478bd9Sstevel@tonic-gate static int 2028*7c478bd9Sstevel@tonic-gate md5_create_ctx_template(crypto_provider_handle_t provider, 2029*7c478bd9Sstevel@tonic-gate crypto_mechanism_t *mechanism, crypto_key_t *key, 2030*7c478bd9Sstevel@tonic-gate crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size, 2031*7c478bd9Sstevel@tonic-gate crypto_req_handle_t req) 2032*7c478bd9Sstevel@tonic-gate { 2033*7c478bd9Sstevel@tonic-gate md5_hmac_ctx_t *md5_hmac_ctx_tmpl; 2034*7c478bd9Sstevel@tonic-gate uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length); 2035*7c478bd9Sstevel@tonic-gate 2036*7c478bd9Sstevel@tonic-gate if ((mechanism->cm_type != MD5_HMAC_MECH_INFO_TYPE) && 2037*7c478bd9Sstevel@tonic-gate (mechanism->cm_type != MD5_HMAC_GEN_MECH_INFO_TYPE)) 2038*7c478bd9Sstevel@tonic-gate return (CRYPTO_MECHANISM_INVALID); 2039*7c478bd9Sstevel@tonic-gate 2040*7c478bd9Sstevel@tonic-gate /* Add support for key by attributes (RFE 4706552) */ 2041*7c478bd9Sstevel@tonic-gate if (key->ck_format != CRYPTO_KEY_RAW) 2042*7c478bd9Sstevel@tonic-gate return (CRYPTO_ARGUMENTS_BAD); 2043*7c478bd9Sstevel@tonic-gate 2044*7c478bd9Sstevel@tonic-gate /* 2045*7c478bd9Sstevel@tonic-gate * Allocate and initialize MD5 context. 2046*7c478bd9Sstevel@tonic-gate */ 2047*7c478bd9Sstevel@tonic-gate md5_hmac_ctx_tmpl = kmem_alloc(sizeof (md5_hmac_ctx_t), 2048*7c478bd9Sstevel@tonic-gate crypto_kmflag(req)); 2049*7c478bd9Sstevel@tonic-gate if (md5_hmac_ctx_tmpl == NULL) 2050*7c478bd9Sstevel@tonic-gate return (CRYPTO_HOST_MEMORY); 2051*7c478bd9Sstevel@tonic-gate 2052*7c478bd9Sstevel@tonic-gate if (keylen_in_bytes > MD5_HMAC_BLOCK_SIZE) { 2053*7c478bd9Sstevel@tonic-gate uchar_t digested_key[MD5_DIGEST_LENGTH]; 2054*7c478bd9Sstevel@tonic-gate 2055*7c478bd9Sstevel@tonic-gate /* 2056*7c478bd9Sstevel@tonic-gate * Hash the passed-in key to get a smaller key. 2057*7c478bd9Sstevel@tonic-gate * The inner context is used since it hasn't been 2058*7c478bd9Sstevel@tonic-gate * initialized yet. 2059*7c478bd9Sstevel@tonic-gate */ 2060*7c478bd9Sstevel@tonic-gate PROV_MD5_DIGEST_KEY(&md5_hmac_ctx_tmpl->hc_icontext, 2061*7c478bd9Sstevel@tonic-gate key->ck_data, keylen_in_bytes, digested_key); 2062*7c478bd9Sstevel@tonic-gate md5_mac_init_ctx(md5_hmac_ctx_tmpl, digested_key, 2063*7c478bd9Sstevel@tonic-gate MD5_DIGEST_LENGTH); 2064*7c478bd9Sstevel@tonic-gate } else { 2065*7c478bd9Sstevel@tonic-gate md5_mac_init_ctx(md5_hmac_ctx_tmpl, key->ck_data, 2066*7c478bd9Sstevel@tonic-gate keylen_in_bytes); 2067*7c478bd9Sstevel@tonic-gate } 2068*7c478bd9Sstevel@tonic-gate 2069*7c478bd9Sstevel@tonic-gate md5_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type; 2070*7c478bd9Sstevel@tonic-gate *ctx_template = (crypto_spi_ctx_template_t)md5_hmac_ctx_tmpl; 2071*7c478bd9Sstevel@tonic-gate *ctx_template_size = sizeof (md5_hmac_ctx_t); 2072*7c478bd9Sstevel@tonic-gate 2073*7c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 2074*7c478bd9Sstevel@tonic-gate } 2075*7c478bd9Sstevel@tonic-gate 2076*7c478bd9Sstevel@tonic-gate static int 2077*7c478bd9Sstevel@tonic-gate md5_free_context(crypto_ctx_t *ctx) 2078*7c478bd9Sstevel@tonic-gate { 2079*7c478bd9Sstevel@tonic-gate uint_t ctx_len; 2080*7c478bd9Sstevel@tonic-gate md5_mech_type_t mech_type; 2081*7c478bd9Sstevel@tonic-gate 2082*7c478bd9Sstevel@tonic-gate if (ctx->cc_provider_private == NULL) 2083*7c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 2084*7c478bd9Sstevel@tonic-gate 2085*7c478bd9Sstevel@tonic-gate /* 2086*7c478bd9Sstevel@tonic-gate * We have to free either MD5 or MD5-HMAC contexts, which 2087*7c478bd9Sstevel@tonic-gate * have different lengths. 2088*7c478bd9Sstevel@tonic-gate */ 2089*7c478bd9Sstevel@tonic-gate 2090*7c478bd9Sstevel@tonic-gate mech_type = PROV_MD5_CTX(ctx)->mc_mech_type; 2091*7c478bd9Sstevel@tonic-gate if (mech_type == MD5_MECH_INFO_TYPE) 2092*7c478bd9Sstevel@tonic-gate ctx_len = sizeof (md5_ctx_t); 2093*7c478bd9Sstevel@tonic-gate else { 2094*7c478bd9Sstevel@tonic-gate ASSERT(mech_type == MD5_HMAC_MECH_INFO_TYPE || 2095*7c478bd9Sstevel@tonic-gate mech_type == MD5_HMAC_GEN_MECH_INFO_TYPE); 2096*7c478bd9Sstevel@tonic-gate ctx_len = sizeof (md5_hmac_ctx_t); 2097*7c478bd9Sstevel@tonic-gate } 2098*7c478bd9Sstevel@tonic-gate 2099*7c478bd9Sstevel@tonic-gate bzero(ctx->cc_provider_private, ctx_len); 2100*7c478bd9Sstevel@tonic-gate kmem_free(ctx->cc_provider_private, ctx_len); 2101*7c478bd9Sstevel@tonic-gate ctx->cc_provider_private = NULL; 2102*7c478bd9Sstevel@tonic-gate 2103*7c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS); 2104*7c478bd9Sstevel@tonic-gate } 2105*7c478bd9Sstevel@tonic-gate 2106*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL && !_BOOT */ 2107