static void init_random_int32(void) { struct timeval key; gettimeofday(&key, NULL); LOCK_RM; fc_keysched((struct ktc_encryptionKey*)&key, random_int32_schedule); UNLOCK_RM; }
struct rx_securityClass * rxkad_NewClientSecurityObject(rxkad_level level, struct ktc_encryptionKey *sessionkey, afs_int32 kvno, int ticketLen, char *ticket) { struct rx_securityClass *tsc; struct rxkad_cprivate *tcp; int code; int size, psize; rxkad_Init(); size = sizeof(struct rx_securityClass); tsc = rxi_Alloc(size); memset((void *)tsc, 0, size); tsc->refCount = 1; /* caller gets one for free */ tsc->ops = &rxkad_client_ops; psize = PDATA_SIZE(ticketLen); tcp = rxi_Alloc(psize); memset((void *)tcp, 0, psize); tsc->privateData = (char *)tcp; tcp->type |= rxkad_client; tcp->level = level; code = fc_keysched(sessionkey, tcp->keysched); if (code) { rxi_Free(tcp, psize); rxi_Free(tsc, sizeof(struct rx_securityClass)); return 0; /* bad key */ } memcpy((void *)tcp->ivec, (void *)sessionkey, sizeof(tcp->ivec)); tcp->kvno = kvno; /* key version number */ tcp->ticketLen = ticketLen; /* length of ticket */ if (tcp->ticketLen > MAXKTCTICKETLEN) { rxi_Free(tcp, psize); rxi_Free(tsc, sizeof(struct rx_securityClass)); return 0; /* bad key */ } memcpy(tcp->ticket, ticket, ticketLen); INC_RXKAD_STATS(clientObjects); return tsc; }
/* XXX this does some copying of data in and out of the packet, but I'll bet it * could just do it in place, especially if I used rx_Pullup... */ int rxkad_CheckResponse(struct rx_securityClass *aobj, struct rx_connection *aconn, struct rx_packet *apacket) { struct rxkad_sconn *sconn; struct rxkad_sprivate *tsp; struct ktc_encryptionKey serverKey; struct rxkad_oldChallengeResponse oldr; /* response format */ struct rxkad_v2ChallengeResponse v2r; afs_int32 tlen; /* ticket len */ afs_int32 kvno; /* key version of ticket */ char tix[MAXKTCTICKETLEN]; afs_int32 incChallengeID; rxkad_level level; int code; /* ticket contents */ struct ktc_principal client; struct ktc_encryptionKey sessionkey; afs_int32 host; afs_uint32 start; afs_uint32 end; unsigned int pos; struct rxkad_serverinfo *rock; sconn = (struct rxkad_sconn *)aconn->securityData; tsp = (struct rxkad_sprivate *)aobj->privateData; if (sconn->cksumSeen) { /* expect v2 response, leave fields in v2r in network order for cksum * computation which follows decryption. */ if (rx_GetDataSize(apacket) < sizeof(v2r)) return RXKADPACKETSHORT; rx_packetread(apacket, 0, sizeof(v2r), &v2r); pos = sizeof(v2r); /* version == 2 */ /* ignore spare */ kvno = ntohl(v2r.kvno); tlen = ntohl(v2r.ticketLen); if (rx_GetDataSize(apacket) < sizeof(v2r) + tlen) return RXKADPACKETSHORT; } else { /* expect old format response */ if (rx_GetDataSize(apacket) < sizeof(oldr)) return RXKADPACKETSHORT; rx_packetread(apacket, 0, sizeof(oldr), &oldr); pos = sizeof(oldr); kvno = ntohl(oldr.kvno); tlen = ntohl(oldr.ticketLen); if (rx_GetDataSize(apacket) != sizeof(oldr) + tlen) return RXKADPACKETSHORT; } if ((tlen < MINKTCTICKETLEN) || (tlen > MAXKTCTICKETLEN)) return RXKADTICKETLEN; rx_packetread(apacket, pos, tlen, tix); /* get ticket */ /* * We allow the ticket to be optionally decoded by an alternate * ticket decoder, if the function variable * rxkad_AlternateTicketDecoder is set. That function should * return a code of -1 if it wants the ticket to be decoded by * the standard decoder. */ if (rxkad_AlternateTicketDecoder) { code = rxkad_AlternateTicketDecoder(kvno, tix, tlen, client.name, client.instance, client.cell, &sessionkey, &host, &start, &end); if (code && code != -1) { return code; } } else { code = -1; /* No alternate ticket decoder present */ } /* * If the alternate decoder is not present, or returns -1, then * assume the ticket is of the default style. */ if (code == -1 && ((kvno == RXKAD_TKT_TYPE_KERBEROS_V5) || (kvno == RXKAD_TKT_TYPE_KERBEROS_V5_ENCPART_ONLY))) { code = tkt_DecodeTicket5(tix, tlen, tsp->get_key, tsp->get_key_rock, kvno, client.name, client.instance, client.cell, &sessionkey, &host, &start, &end, tsp->flags & RXS_CONFIG_FLAGS_DISABLE_DOTCHECK); if (code) return code; } /* * If the alternate decoder/kerberos 5 decoder is not present, or * returns -1, then assume the ticket is of the default style. */ if (code == -1) { /* get ticket's key */ code = (*tsp->get_key) (tsp->get_key_rock, kvno, &serverKey); if (code) return RXKADUNKNOWNKEY; /* invalid kvno */ code = tkt_DecodeTicket(tix, tlen, &serverKey, client.name, client.instance, client.cell, &sessionkey, &host, &start, &end); if (code) return code; } code = tkt_CheckTimes(start, end, time(0)); if (code == 0) return RXKADNOAUTH; else if (code == -1) return RXKADEXPIRED; else if (code < -1) return RXKADBADTICKET; code = fc_keysched(&sessionkey, sconn->keysched); if (code) return RXKADBADKEY; memcpy(sconn->ivec, &sessionkey, sizeof(sconn->ivec)); if (sconn->cksumSeen) { /* using v2 response */ afs_uint32 cksum; /* observed cksum */ struct rxkad_endpoint endpoint; /* connections endpoint */ int i; afs_uint32 xor[2]; memcpy(xor, sconn->ivec, 2 * sizeof(afs_int32)); fc_cbc_encrypt(&v2r.encrypted, &v2r.encrypted, sizeof(v2r.encrypted), sconn->keysched, xor, DECRYPT); cksum = rxkad_CksumChallengeResponse(&v2r); if (cksum != v2r.encrypted.endpoint.cksum) return RXKADSEALEDINCON; (void)rxkad_SetupEndpoint(aconn, &endpoint); v2r.encrypted.endpoint.cksum = 0; if (memcmp(&endpoint, &v2r.encrypted.endpoint, sizeof(endpoint)) != 0) return RXKADSEALEDINCON; for (i = 0; i < RX_MAXCALLS; i++) { v2r.encrypted.callNumbers[i] = ntohl(v2r.encrypted.callNumbers[i]); if (v2r.encrypted.callNumbers[i] < 0) return RXKADSEALEDINCON; } (void)rxi_SetCallNumberVector(aconn, v2r.encrypted.callNumbers); incChallengeID = ntohl(v2r.encrypted.incChallengeID); level = ntohl(v2r.encrypted.level); } else { /* expect old format response */ fc_ecb_encrypt(&oldr.encrypted, &oldr.encrypted, sconn->keysched, DECRYPT); incChallengeID = ntohl(oldr.encrypted.incChallengeID); level = ntohl(oldr.encrypted.level); } if (incChallengeID != sconn->challengeID + 1) return RXKADOUTOFSEQUENCE; /* replay attempt */ if ((level < sconn->level) || (level > rxkad_crypt)) return RXKADLEVELFAIL; sconn->level = level; rxkad_SetLevel(aconn, sconn->level); INC_RXKAD_STATS(responses[rxkad_LevelIndex(sconn->level)]); /* now compute endpoint-specific info used for computing 16 bit checksum */ rxkad_DeriveXORInfo(aconn, sconn->keysched, sconn->ivec, sconn->preSeq); /* otherwise things are ok */ sconn->expirationTime = end; sconn->authenticated = 1; if (tsp->user_ok) { code = tsp->user_ok(client.name, client.instance, client.cell, kvno); if (code) return RXKADNOAUTH; } else { /* save the info for later retreival */ int size = sizeof(struct rxkad_serverinfo); rock = (struct rxkad_serverinfo *)osi_Alloc(size); memset(rock, 0, size); rock->kvno = kvno; memcpy(&rock->client, &client, sizeof(rock->client)); sconn->rock = rock; } return 0; }
int main(void) { int32 sched[ROUNDS]; char ciph[100], clear[100]; u_int32 data[2]; u_int32 iv[2]; struct rx_connection conn; struct rx_securityClass obj; struct rxkad_cprivate cpriv; struct rx_packet packet; int fail = 0; conn.securityObject = &obj; obj.privateData = (void *)&cpriv; cpriv.type = 0; if (sizeof(int32) != 4) { fprintf(stderr, "error: sizeof(int32) != 4\n"); fail++; } if (sizeof(u_int32) != 4) { fprintf(stderr, "error: sizeof(u_int32) != 4\n"); fail++; } /* * Use key1 and key2 as iv */ fc_keysched((struct ktc_encryptionKey *)key1, sched); memcpy(iv, key2, sizeof(iv)); fc_cbc_encrypt(the_quick, ciph, sizeof(the_quick), sched, iv, ENCRYPT); if (memcmp(ciph1, ciph, sizeof(ciph1)) != 0) { fprintf(stderr, "encrypt FAILED\n"); fail++; } memcpy(iv, key2, sizeof(iv)); fc_cbc_encrypt(ciph, clear, sizeof(the_quick), sched, iv, DECRYPT); if (strcmp(the_quick, clear) != 0) { fprintf(stderr, "crypt decrypt FAILED\n"); fail++; } /* * Use key2 and key1 as iv */ fc_keysched((struct ktc_encryptionKey *)key2, sched); memcpy(iv, key1, sizeof(iv)); fc_cbc_encrypt(the_quick, ciph, sizeof(the_quick), sched, iv, ENCRYPT); if (memcmp(ciph2, ciph, sizeof(ciph2)) != 0) { fprintf(stderr, "encrypt FAILED\n"); fail++; } memcpy(iv, key1, sizeof(iv)); fc_cbc_encrypt(ciph, clear, sizeof(the_quick), sched, iv, DECRYPT); if (strcmp(the_quick, clear) != 0) { fprintf(stderr, "crypt decrypt FAILED\n"); fail++; } /* * Test Encrypt- and Decrypt-Packet, use key1 and key2 as iv */ fc_keysched((struct ktc_encryptionKey *)key1, sched); memcpy(iv, key2, sizeof(iv)); strcpy(clear, the_quick); packet.wirevec[1].iov_base = clear; packet.wirevec[1].iov_len = sizeof(the_quick); packet.wirevec[2].iov_len = 0; /* For unknown reasons bytes 4-7 are zeroed in rxkad_EncryptPacket */ rxkad_EncryptPacket(&conn, sched, iv, sizeof(the_quick), &packet); rxkad_DecryptPacket(&conn, sched, iv, sizeof(the_quick), &packet); clear[4] ^= 'q'; clear[5] ^= 'u'; clear[6] ^= 'i'; clear[7] ^= 'c'; if (strcmp(the_quick, clear) != 0) fprintf(stderr, "rxkad_EncryptPacket/rxkad_DecryptPacket FAILED\n"); { struct timeval start, stop; int i; fc_keysched((struct ktc_encryptionKey *)key1, sched); gettimeofday(&start, NULL); for (i = 0; i < 1000000; i++) fc_keysched((struct ktc_encryptionKey *)key1, sched); gettimeofday(&stop, NULL); printf("fc_keysched = %2.2f us\n", (stop.tv_sec - start.tv_sec + (stop.tv_usec - start.tv_usec) / 1e6) * 1); fc_ecb_encrypt(data, data, sched, ENCRYPT); gettimeofday(&start, NULL); for (i = 0; i < 1000000; i++) fc_ecb_encrypt(data, data, sched, ENCRYPT); gettimeofday(&stop, NULL); printf("fc_ecb_encrypt = %2.2f us\n", (stop.tv_sec - start.tv_sec + (stop.tv_usec - start.tv_usec) / 1e6) * 1); fc_cbc_encrypt(the_quick, ciph, sizeof(the_quick), sched, iv, ENCRYPT); gettimeofday(&start, NULL); for (i = 0; i < 100000; i++) fc_cbc_encrypt(the_quick, ciph, sizeof(the_quick), sched, iv, ENCRYPT); gettimeofday(&stop, NULL); printf("fc_cbc_encrypt = %2.2f us\n", (stop.tv_sec - start.tv_sec + (stop.tv_usec - start.tv_usec) / 1e6) * 10); } exit(fail); }