/** * eap_pax_mac - EAP-PAX MAC * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported * @key: Secret key * @key_len: Length of the secret key in bytes * @data1: Optional data, first block; %NULL if not used * @data1_len: Length of data1 in bytes * @data2: Optional data, second block; %NULL if not used * @data2_len: Length of data2 in bytes * @data3: Optional data, third block; %NULL if not used * @data3_len: Length of data3 in bytes * @mac: Buffer for the MAC value (EAP_PAX_MAC_LEN = 16 bytes) * Returns: 0 on success, -1 on failure * * Wrapper function to calculate EAP-PAX MAC. */ int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len, const u8 *data1, size_t data1_len, const u8 *data2, size_t data2_len, const u8 *data3, size_t data3_len, u8 *mac) { u8 hash[SHA1_MAC_LEN]; const u8 *addr[3]; size_t len[3]; size_t count; /* TODO: add support for EAP_PAX_HMAC_SHA256_128 */ if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128) return -1; addr[0] = data1; len[0] = data1_len; addr[1] = data2; len[1] = data2_len; addr[2] = data3; len[2] = data3_len; count = (data1 ? 1 : 0) + (data2 ? 1 : 0) + (data3 ? 1 : 0); hmac_sha1_vector(key, key_len, count, addr, len, hash); os_memcpy(mac, hash, EAP_PAX_MAC_LEN); return 0; }
void stun_sha1 (const uint8_t *msg, size_t len, size_t msg_len, uint8_t *sha, const void *key, size_t keylen, int padding) { uint16_t fakelen = htons (msg_len); const uint8_t *vector[4]; size_t lengths[4]; uint8_t pad_char[64] = {0}; size_t num_elements; assert (len >= 44u); vector[0] = msg; lengths[0] = 2; vector[1] = (const uint8_t *)&fakelen; lengths[1] = 2; vector[2] = msg + 4; lengths[2] = len - 28; num_elements = 3; /* RFC 3489 specifies that the message's size should be 64 bytes, and \x00 padding should be done */ if (padding && ((len - 24) % 64) > 0) { uint16_t pad_size = 64 - ((len - 24) % 64); vector[3] = pad_char; lengths[3] = pad_size; num_elements++; } hmac_sha1_vector(key, keylen, num_elements, vector, lengths, sha); }
static int eap_eke_prf_hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *res, size_t len) { u8 hash[SHA1_MAC_LEN]; u8 idx; const u8 *addr[3]; size_t vlen[3]; int ret; idx = 0; addr[0] = hash; vlen[0] = SHA1_MAC_LEN; addr[1] = data; vlen[1] = data_len; addr[2] = &idx; vlen[2] = 1; while (len > 0) { idx++; if (idx == 1) ret = hmac_sha1_vector(key, key_len, 2, &addr[1], &vlen[1], hash); else ret = hmac_sha1_vector(key, key_len, 3, addr, vlen, hash); if (ret < 0) return -1; if (len > SHA1_MAC_LEN) { os_memcpy(res, hash, SHA1_MAC_LEN); res += SHA1_MAC_LEN; len -= SHA1_MAC_LEN; } else { os_memcpy(res, hash, len); len = 0; } } return 0; }
/** * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1) * @key: Key for PRF * @key_len: Length of the key in bytes * @label: A unique label for each purpose of the PRF * @data: Extra data to bind into the key * @data_len: Length of the data * @buf: Buffer for the generated pseudo-random key * @buf_len: Number of bytes of key to generate * Returns: 0 on success, -1 of failure * * This function is used to derive new, cryptographically separate keys from a * given key (e.g., PMK in IEEE 802.11i). */ int sha1_prf(const u8 *key, size_t key_len, const char *label, const u8 *data, size_t data_len, u8 *buf, size_t buf_len) { u8 counter = 0; size_t pos, plen; u8 hash[SHA1_MAC_LEN]; size_t label_len = os_strlen(label) + 1; const unsigned char *addr[3]; size_t len[3]; addr[0] = (u8 *) label; len[0] = label_len; addr[1] = data; len[1] = data_len; addr[2] = &counter; len[2] = 1; pos = 0; while (pos < buf_len) { plen = buf_len - pos; if (plen >= SHA1_MAC_LEN) { /* 每次计算出20字节的SHA1_MAC消息认证码 */ if (hmac_sha1_vector(key, key_len, 3, addr, len, &buf[pos])) return -1; pos += SHA1_MAC_LEN; } else { /* 最后一次剩余plen小于20的时候,只复制plen长度的值 */ if (hmac_sha1_vector(key, key_len, 3, addr, len, hash)) return -1; os_memcpy(&buf[pos], hash, plen); break; } counter++; } return 0; }
/** * rsn_pmkid - calculate PMK identifier * @pmk: pairwise master key * @aa: authenticator address * @spa: supplicant address * * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA) */ static void rsn_pmkid(const u8 *pmk, const u8 *aa, const u8 *spa, u8 *pmkid) { char *title = "PMK Name"; const unsigned char *addr[3]; const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; unsigned char hash[SHA1_MAC_LEN]; addr[0] = (unsigned char *) title; addr[1] = aa; addr[2] = spa; hmac_sha1_vector(pmk, PMK_LEN, 3, addr, len, hash); memcpy(pmkid, hash, PMKID_LEN); }
/** * eap_sake_kdf - EAP-SAKE Key Derivation Function (KDF) * @key: Key for KDF * @key_len: Length of the key in bytes * @label: A unique label for each purpose of the KDF * @data: Extra data (start) to bind into the key * @data_len: Length of the data * @data2: Extra data (end) to bind into the key * @data2_len: Length of the data2 * @buf: Buffer for the generated pseudo-random key * @buf_len: Number of bytes of key to generate * * This function is used to derive new, cryptographically separate keys from a * given key (e.g., SMS). This is identical to the PRF used in IEEE 802.11i. */ static void eap_sake_kdf(const u8 *key, size_t key_len, const char *label, const u8 *data, size_t data_len, const u8 *data2, size_t data2_len, u8 *buf, size_t buf_len) { u8 counter = 0; size_t pos, plen; u8 hash[SHA1_MAC_LEN]; size_t label_len = os_strlen(label) + 1; const unsigned char *addr[4]; size_t len[4]; addr[0] = (u8 *) label; /* Label | Y */ len[0] = label_len; addr[1] = data; /* Msg[start] */ len[1] = data_len; addr[2] = data2; /* Msg[end] */ len[2] = data2_len; addr[3] = &counter; /* Length */ len[3] = 1; pos = 0; while (pos < buf_len) { plen = buf_len - pos; if (plen >= SHA1_MAC_LEN) { hmac_sha1_vector(key, key_len, 4, addr, len, &buf[pos]); pos += SHA1_MAC_LEN; } else { hmac_sha1_vector(key, key_len, 4, addr, len, hash); os_memcpy(&buf[pos], hash, plen); break; } counter++; } }
int ikev2_prf_hash(int alg, const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *hash) { switch (alg) { case PRF_HMAC_SHA1: hmac_sha1_vector(key, key_len, num_elem, addr, len, hash); break; case PRF_HMAC_MD5: hmac_md5_vector(key, key_len, num_elem, addr, len, hash); break; default: return -1; } return 0; }
/** * rsn_pmkid - Calculate PMK identifier * @pmk: Pairwise master key * @pmk_len: Length of pmk in bytes * @aa: Authenticator address * @spa: Supplicant address * @pmkid: Buffer for PMKID * @use_sha256: Whether to use SHA256-based KDF * * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA) */ void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, u8 *pmkid, int use_sha256) { char *title = "PMK Name"; const u8 *addr[3]; const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; unsigned char hash[SHA256_MAC_LEN]; addr[0] = (u8 *) title; addr[1] = aa; addr[2] = spa; #ifdef CONFIG_IEEE80211W if (use_sha256) hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); else #endif /* CONFIG_IEEE80211W */ hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash); os_memcpy(pmkid, hash, PMKID_LEN); }
static int eap_tlv_add_cryptobinding(struct eap_sm *sm, struct eap_peap_data *data, struct wpabuf *buf) { u8 *mac; u8 eap_type = EAP_TYPE_PEAP; const u8 *addr[2]; size_t len[2]; u16 tlv_type; /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ addr[0] = wpabuf_put(buf, 0); len[0] = 60; addr[1] = &eap_type; len[1] = 1; tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; if (data->peap_version >= 2) tlv_type |= EAP_TLV_TYPE_MANDATORY; wpabuf_put_be16(buf, tlv_type); wpabuf_put_be16(buf, 56); wpabuf_put_u8(buf, 0); /* Reserved */ wpabuf_put_u8(buf, data->peap_version); /* Version */ wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */ wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */ wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */ mac = wpabuf_put(buf, 20); /* Compound_MAC */ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20); wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1", addr[0], len[0]); wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2", addr[1], len[1]); hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac); wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN); data->crypto_binding_used = 1; return 0; }
int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req, const u8 *mac, const u8 *extra, size_t extra_len) { unsigned char hmac[SHA1_MAC_LEN]; const u8 *addr[2]; size_t len[2]; u8 *tmp; if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN || mac < wpabuf_head_u8(req) || mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN) return -1; tmp = os_malloc(wpabuf_len(req)); if (tmp == NULL) return -1; addr[0] = tmp; len[0] = wpabuf_len(req); addr[1] = extra; len[1] = extra_len; /* HMAC-SHA1-128 */ os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req)); os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg", tmp, wpabuf_len(req)); wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data", extra, extra_len); wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut", k_aut, EAP_SIM_K_AUT_LEN); hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac); wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC", hmac, EAP_SIM_MAC_LEN); os_free(tmp); return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1; }
/** * eap_pax_kdf - PAX Key Derivation Function * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported * @key: Secret key (X) * @key_len: Length of the secret key in bytes * @identifier: Public identifier for the key (Y) * @entropy: Exchanged entropy to seed the KDF (Z) * @entropy_len: Length of the entropy in bytes * @output_len: Output len in bytes (W) * @output: Buffer for the derived key * Returns: 0 on success, -1 failed * * RFC 4746, Section 2.6: PAX-KDF-W(X, Y, Z) */ int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len, const char *identifier, const u8 *entropy, size_t entropy_len, size_t output_len, u8 *output) { u8 mac[SHA1_MAC_LEN]; u8 counter, *pos; const u8 *addr[3]; size_t len[3]; size_t num_blocks, left; num_blocks = (output_len + EAP_PAX_MAC_LEN - 1) / EAP_PAX_MAC_LEN; if (identifier == NULL || num_blocks >= 255) return -1; /* TODO: add support for EAP_PAX_HMAC_SHA256_128 */ if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128) return -1; addr[0] = (const u8 *) identifier; len[0] = os_strlen(identifier); addr[1] = entropy; len[1] = entropy_len; addr[2] = &counter; len[2] = 1; pos = output; left = output_len; for (counter = 1; counter <= (u8) num_blocks; counter++) { size_t clen = left > EAP_PAX_MAC_LEN ? EAP_PAX_MAC_LEN : left; hmac_sha1_vector(key, key_len, 3, addr, len, mac); os_memcpy(pos, mac, clen); pos += clen; left -= clen; } return 0; }
static int eap_eke_prf(u8 prf, const u8 *key, size_t key_len, const u8 *data, size_t data_len, const u8 *data2, size_t data2_len, u8 *res) { const u8 *addr[2]; size_t len[2]; size_t num_elem = 1; addr[0] = data; len[0] = data_len; if (data2) { num_elem++; addr[1] = data2; len[1] = data2_len; } if (prf == EAP_EKE_PRF_HMAC_SHA1) return hmac_sha1_vector(key, key_len, num_elem, addr, len, res); if (prf == EAP_EKE_PRF_HMAC_SHA2_256) return hmac_sha256_vector(key, key_len, num_elem, addr, len, res); return -1; }
/** * rsn_smkid - Derive SMK identifier * @smk: Station master key (32 bytes) * @pnonce: Peer Nonce * @mac_p: Peer MAC address * @inonce: Initiator Nonce * @mac_i: Initiator MAC address * @use_sha256: Whether to use SHA256-based KDF * * 8.5.1.4 Station to station (STK) key hierarchy * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I) */ static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p, const u8 *inonce, const u8 *mac_i, u8 *smkid, int use_sha256) { char *title = "SMK Name"; const u8 *addr[5]; const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN, ETH_ALEN }; unsigned char hash[SHA256_MAC_LEN]; addr[0] = (u8 *) title; addr[1] = pnonce; addr[2] = mac_p; addr[3] = inonce; addr[4] = mac_i; #ifdef CONFIG_IEEE80211W if (use_sha256) hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash); else #endif /* CONFIG_IEEE80211W */ hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash); os_memcpy(smkid, hash, PMKID_LEN); }
void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac, const u8 *extra, size_t extra_len) { unsigned char hmac[SHA1_MAC_LEN]; const u8 *addr[2]; size_t len[2]; addr[0] = msg; len[0] = msg_len; addr[1] = extra; len[1] = extra_len; /* HMAC-SHA1-128 */ os_memset(mac, 0, EAP_SIM_MAC_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len); wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data", extra, extra_len); wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut", k_aut, EAP_SIM_K_AUT_LEN); hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac); os_memcpy(mac, hmac, EAP_SIM_MAC_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC", mac, EAP_SIM_MAC_LEN); }
/** * hmac_sha1 - HMAC-SHA1 over data buffer (RFC 2104) * @key: Key for HMAC operations * @key_len: Length of the key in bytes * @data: Pointers to the data area * @data_len: Length of the data area * @mac: Buffer for the hash (20 bytes) * Returns: 0 on success, -1 of failure */ int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac) { return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); }
static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm, struct eap_peap_data *data, u8 id) { struct wpabuf *buf, *encr_req; size_t mlen; mlen = 6; /* Result TLV */ if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS && data->crypto_binding != NO_BINDING) { mlen += 60; /* Cryptobinding TLV */ #ifdef EAP_SERVER_TNC if (data->soh_response) mlen += wpabuf_len(data->soh_response); #endif /* EAP_SERVER_TNC */ } buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen, EAP_CODE_REQUEST, id); if (buf == NULL) return NULL; wpabuf_put_u8(buf, 0x80); /* Mandatory */ wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV); /* Length */ wpabuf_put_be16(buf, 2); /* Status */ wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ? EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE); if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS && data->crypto_binding != NO_BINDING) { u8 *mac; u8 eap_type = EAP_TYPE_PEAP; const u8 *addr[2]; size_t len[2]; u16 tlv_type; #ifdef EAP_SERVER_TNC if (data->soh_response) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH " "Response TLV"); wpabuf_put_buf(buf, data->soh_response); wpabuf_free(data->soh_response); data->soh_response = NULL; } #endif /* EAP_SERVER_TNC */ if (eap_peap_derive_cmk(sm, data) < 0 || random_get_bytes(data->binding_nonce, 32)) { wpabuf_free(buf); return NULL; } /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ addr[0] = wpabuf_put(buf, 0); len[0] = 60; addr[1] = &eap_type; len[1] = 1; tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; wpabuf_put_be16(buf, tlv_type); wpabuf_put_be16(buf, 56); wpabuf_put_u8(buf, 0); /* Reserved */ wpabuf_put_u8(buf, data->peap_version); /* Version */ wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */ wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */ wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */ mac = wpabuf_put(buf, 20); /* Compound_MAC */ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20); wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1", addr[0], len[0]); wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2", addr[1], len[1]); hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac); wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN); data->crypto_binding_sent = 1; } wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data", buf); encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf); wpabuf_free(buf); return encr_req; }
/** * tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246) * @secret: Key for PRF * @secret_len: Length of the key in bytes * @label: A unique label for each purpose of the PRF * @seed: Seed value to bind into the key * @seed_len: Length of the seed * @out: Buffer for the generated pseudo-random key * @outlen: Number of bytes of key to generate * Returns: 0 on success, -1 on failure. * * This function is used to derive new, cryptographically separate keys from a * given key in TLS. This PRF is defined in RFC 2246, Chapter 5. */ int tls_prf(const u8 *secret, size_t secret_len, const char *label, const u8 *seed, size_t seed_len, u8 *out, size_t outlen) { size_t L_S1, L_S2, i; const u8 *S1, *S2; u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN]; u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN]; int MD5_pos, SHA1_pos; const u8 *MD5_addr[3]; size_t MD5_len[3]; const unsigned char *SHA1_addr[3]; size_t SHA1_len[3]; if (secret_len & 1) return -1; MD5_addr[0] = A_MD5; MD5_len[0] = MD5_MAC_LEN; MD5_addr[1] = (unsigned char *) label; MD5_len[1] = os_strlen(label); MD5_addr[2] = seed; MD5_len[2] = seed_len; SHA1_addr[0] = A_SHA1; SHA1_len[0] = SHA1_MAC_LEN; SHA1_addr[1] = (unsigned char *) label; SHA1_len[1] = os_strlen(label); SHA1_addr[2] = seed; SHA1_len[2] = seed_len; /* RFC 2246, Chapter 5 * A(0) = seed, A(i) = HMAC(secret, A(i-1)) * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + .. * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed) */ L_S1 = L_S2 = (secret_len + 1) / 2; S1 = secret; S2 = secret + L_S1; if (secret_len & 1) { /* The last byte of S1 will be shared with S2 */ S2--; } hmac_md5_vector_non_fips_allow(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5); hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1); MD5_pos = MD5_MAC_LEN; SHA1_pos = SHA1_MAC_LEN; for (i = 0; i < outlen; i++) { if (MD5_pos == MD5_MAC_LEN) { hmac_md5_vector_non_fips_allow(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5); MD5_pos = 0; hmac_md5_non_fips_allow(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5); } if (SHA1_pos == SHA1_MAC_LEN) { hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len, P_SHA1); SHA1_pos = 0; hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1); } out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos]; MD5_pos++; SHA1_pos++; } return 0; }