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