ntp源码解读(一)
/* * session_key - generate session key * * This routine generates a session key from the source address, * destination address, key ID and private value. The value of the * session key is the MD5 hash of these values, while the next key ID is * the first four octets of the hash. * * Returns the next key ID or 0 if there is no destination address. */ keyid_t session_key( sockaddr_u *srcadr, /* source address */ sockaddr_u *dstadr, /* destination address */ keyid_t keyno, /* key ID */ keyid_t private, /* private value */ u_long lifetime /* key lifetime */ ) { EVP_MD_CTX ctx; /* message digest context */ u_char dgst[EVP_MAX_MD_SIZE]; /* message digest */ keyid_t keyid; /* key identifer */ u_int32 header[10]; /* data in network byte order */ u_int hdlen, len; if (!dstadr) return 0; /* * Generate the session key and key ID. If the lifetime is * greater than zero, install the key and call it trusted. */ hdlen = 0; switch(AF(srcadr)) { case AF_INET: header[0] = NSRCADR(srcadr); header[1] = NSRCADR(dstadr); header[2] = htonl(keyno); header[3] = htonl(private); hdlen = 4 * sizeof(u_int32); break; case AF_INET6: memcpy(&header[0], PSOCK_ADDR6(srcadr), sizeof(struct in6_addr)); memcpy(&header[4], PSOCK_ADDR6(dstadr), sizeof(struct in6_addr)); header[8] = htonl(keyno); header[9] = htonl(private); hdlen = 10 * sizeof(u_int32); break; } EVP_DigestInit(&ctx, EVP_get_digestbynid(crypto_nid)); EVP_DigestUpdate(&ctx, (u_char *)header, hdlen); EVP_DigestFinal(&ctx, dgst, &len); memcpy(&keyid, dgst, 4); keyid = ntohl(keyid); if (lifetime != 0) { MD5auth_setkey(keyno, crypto_nid, dgst, len); authtrust(keyno, lifetime); } DPRINTF(2, ("session_key: %s > %s %08x %08x hash %08x life %lu\n", stoa(srcadr), stoa(dstadr), keyno, private, keyid, lifetime)); #ifdef DEBUG if (debug) printf("session_key:MD5 DIGEST ==== %08x\n",dgst); #endif return (keyid); }
以上例程是根据the source address, * destination address, key ID and private value这四者做哈希,下一个密钥ID就是这个哈希值的前四个字节。
同时以上代码展示了,MD5的算法流程,先定义EVP_MD_CTX ctx,然后定义哈希值的存放地址char * dgst。
EVP_DigestInit(&ctx, EVP_get_digestbynid(crypto_nid)); EVP_DigestUpdate(&ctx, (u_char *)header, hdlen); EVP_DigestFinal(&ctx, dgst, &len);
经过以上步骤,再将结果写入dgst中。
如果密钥的生存时间不为0,那么就调用MD5auth_setkey来验证密钥是否是可信任的。
/* * authistrusted - determine whether a key is trusted */ int authistrusted( keyid_t keyno ) { struct savekey *sk; if (keyno == cache_keyid) return ((cache_flags & KEY_TRUSTED) != 0); authkeyuncached++; sk = key_hash[KEYHASH(keyno)]; while (sk != 0) { if (keyno == sk->keyid) break; sk = sk->next; } if (sk == 0) { authkeynotfound++; #ifdef DEBUG if (debug) printf("authistrusted authkeynotfound++\n"); #endif return (0); } else if (!(sk->flags & KEY_TRUSTED)) { #ifdef DEBUG if (debug) printf("authistrusted authkeynotfound++\n"); #endif authkeynotfound++; return (0); } return (1); }
如果密钥ID已经被cache,那么密钥就是可信的。否则就根据key_no做哈希找到sk,查看sk的KEY_TRUSTED有没有置位,如果置位说明密钥可信。整个authistrusted返回1。
整个函数的传入参数是一个32位的整形,KEYHASH这个宏取出其中的前6位,然后在key_hash这个数组中找到对应的savekey。