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。

posted on 2016-02-25 15:52  与非朋仔  阅读(2181)  评论(0编辑  收藏  举报

导航