FreeBSD/contrib/ntp/ntpd/ntp_crypto.c
/*
 ***********************************************************************
 *								       *
 * The following routines implement the Schnorr (IFF) identity scheme  *
 *								       *
 ***********************************************************************
 *
 * The Schnorr (IFF) identity scheme is intended for use when
 * certificates are generated by some other trusted certificate
 * authority and the certificate cannot be used to convey public
 * parameters. There are two kinds of files: encrypted server files that
 * contain private and public values and nonencrypted client files that
 * contain only public values. New generations of server files must be
 * securely transmitted to all servers of the group; client files can be
 * distributed by any means. The scheme is self contained and
 * independent of new generations of host keys, sign keys and
 * certificates.
 *
 * The IFF values hide in a DSA cuckoo structure which uses the same
 * parameters. The values are used by an identity scheme based on DSA
 * cryptography and described in Stimson p. 285. The p is a 512-bit
 * prime, g a generator of Zp* and q a 160-bit prime that divides p - 1
 * and is a qth root of 1 mod p; that is, g^q = 1 mod p. The TA rolls a
 * private random group key b (0 < b < q) and public key v = g^b, then
 * sends (p, q, g, b) to the servers and (p, q, g, v) to the clients.
 * Alice challenges Bob to confirm identity using the protocol described
 * below.
 *
 * How it works
 *
 * The scheme goes like this. Both Alice and Bob have the public primes
 * p, q and generator g. The TA gives private key b to Bob and public
 * key v to Alice.
 *
 * Alice rolls new random challenge r (o < r < q) and sends to Bob in
 * the IFF request message. Bob rolls new random k (0 < k < q), then
 * computes y = k + b r mod q and x = g^k mod p and sends (y, hash(x))
 * to Alice in the response message. Besides making the response
 * shorter, the hash makes it effectivey impossible for an intruder to
 * solve for b by observing a number of these messages.
 * 
 * Alice receives the response and computes g^y v^r mod p. After a bit
 * of algebra, this simplifies to g^k. If the hash of this result
 * matches hash(x), Alice knows that Bob has the group key b. The signed
 * response binds this knowledge to Bob's private key and the public key
 * previously received in his certificate.
 *
 * crypto_alice - construct Alice's challenge in IFF scheme
 *
 * Returns
 * XEVNT_OK	success
 * XEVNT_ID	bad or missing group key
 * XEVNT_PUB	bad or missing public key
 */
The following routines implement the Schnorr (IFF) identity scheme



The Schnorr (IFF) identity scheme is intended for use when
certificates are generated by some other trusted certificate
authority and the certificate cannot be used to convey public
parameters. There are two kinds of files: encrypted server files that
contain private and public values and nonencrypted client files that
contain only public values. New generations of server files must be
securely transmitted to all servers of the group; client files can be
distributed by any means. The scheme is self contained and
independent of new generations of host keys, sign keys and
certificates.

The IFF values hide in a DSA cuckoo structure which uses the same
parameters. The values are used by an identity scheme based on DSA
cryptography and described in Stimson p. 285. The p is a 512-bit
prime, g a generator of Zp* and q a 160-bit prime that divides p - 1
and is a qth root of 1 mod p; that is, g^q = 1 mod p. The TA rolls a
private random group key b (0 < b < q) and public key v = g^b, then
sends (p, q, g, b) to the servers and (p, q, g, v) to the clients.
Alice challenges Bob to confirm identity using the protocol described
below.



The scheme goes like this. Both Alice and Bob have the public primes
p, q and generator g. The TA gives private key b to Bob and public
key v to Alice.

Alice rolls new random challenge r (o < r < q) and sends to Bob in
the IFF request message. Bob rolls new random k (0 < k < q), then
computes y = k + b r mod q and x = g^k mod p and sends (y, hash(x))
to Alice in the response message. Besides making the response
shorter, the hash makes it effectivey impossible for an intruder to
solve for b by observing a number of these messages.

Alice receives the response and computes g^y v^r mod p. After a bit
of algebra, this simplifies to g^k. If the hash of this result
matches hash(x), Alice knows that Bob has the group key b. The signed
response binds this knowledge to Bob's private key and the public key
previously received in his certificate.

construct Alice's challenge in IFF scheme

Returns
XEVNT_OK     success
XEVNT_ID     bad or missing group key
XEVNT_PUB    bad or missing public key
The following routines implement the Schnorr ( IFF ) identity scheme The Schnorr ( IFF ) identity scheme is intended for use when certificates are generated by some other trusted certificate authority and the certificate cannot be used to convey public parameters . There are two kinds of files : encrypted server files that contain private and public values and nonencrypted client files that contain only public values . New generations of server files must be securely transmitted to all servers of the group ; client files can be distributed by any means . The scheme is self contained and independent of new generations of host keys sign keys and certificates . The IFF values hide in a DSA cuckoo structure which uses the same parameters . The values are used by an identity scheme based on DSA cryptography and described in Stimson p . 285 . The p is a 512 - bit prime g a generator of Zp * and q a 160 - bit prime that divides p - 1 and is a qth root of 1 mod p ; that is g^q = 1 mod p . The TA rolls a private random group key b ( 0 < b < q ) and public key v = g^b then sends ( p q g b ) to the servers and ( p q g v ) to the clients . Alice challenges Bob to confirm identity using the protocol described below . The scheme goes like this . Both Alice and Bob have the public primes p q and generator g . The TA gives private key b to Bob and public key v to Alice . Alice rolls new random challenge r ( o < r < q ) and sends to Bob in the IFF request message . Bob rolls new random k ( 0 < k < q ) then computes y = k + b r mod q and x = g^k mod p and sends ( y hash ( x )) to Alice in the response message . Besides making the response shorter the hash makes it effectivey impossible for an intruder to solve for b by observing a number of these messages . Alice receives the response and computes g^y v^r mod p . After a bit of algebra this simplifies to g^k . If the hash of this result matches hash ( x ) Alice knows that Bob has the group key b . The signed response binds this knowledge to Bob ' s private key and the public key previously received in his certificate . construct Alice ' s challenge in IFF scheme Returns XEVNT_OK success XEVNT_ID bad or missing group key XEVNT_PUB bad or missing public key
static int
crypto_alice(
	struct peer *peer,	
	struct value *vp	
	)
{
	DSA	*dsa;		
	BN_CTX	*bctx;		
	EVP_MD_CTX *ctx;	
	tstamp_t tstamp;
	u_int	len;
	const BIGNUM *q;
	if (peer->ident_pkey == NULL) {
		msyslog(LOG_NOTICE, "crypto_alice: scheme unavailable");
		return (XEVNT_ID);
	}
	if ((dsa = EVP_PKEY_get0_DSA(peer->ident_pkey->pkey)) == NULL) {
		msyslog(LOG_NOTICE, "crypto_alice: defective key");
		return (XEVNT_PUB);
	}
	if (peer->iffval != NULL)
		BN_free(peer->iffval);
	peer->iffval = BN_new();
	DSA_get0_pqg(dsa, NULL, &q, NULL);
	len = BN_num_bytes(q);
	BN_rand(peer->iffval, len * 8, -1, 1);	
	bctx = BN_CTX_new();
	BN_mod(peer->iffval, peer->iffval, q, bctx);
	BN_CTX_free(bctx);
	memset(vp, 0, sizeof(struct value));
	tstamp = crypto_time();
	vp->tstamp = htonl(tstamp);
	vp->fstamp = htonl(peer->ident_pkey->fstamp);
	vp->vallen = htonl(len);
	vp->ptr = emalloc(len);
	BN_bn2bin(peer->iffval, vp->ptr);
	if (tstamp == 0)
		return (XEVNT_OK);
	vp->sig = emalloc(sign_siglen);
	ctx = EVP_MD_CTX_new();
	EVP_SignInit(ctx, sign_digest);
	EVP_SignUpdate(ctx, (u_char *)&vp->tstamp, 12);
	EVP_SignUpdate(ctx, vp->ptr, len);
	if (EVP_SignFinal(ctx, vp->sig, &len, sign_pkey)) {
		INSIST(len <= sign_siglen);
		vp->siglen = htonl(len);
	}
	EVP_MD_CTX_free(ctx);
	return (XEVNT_OK);
}
static int crypto_alice ( struct peer * peer , struct value * vp ) { DSA * dsa ; BN_CTX * bctx ; EVP_MD_CTX * ctx ; tstamp_t tstamp ; u_int len ; const BIGNUM * q ; if ( peer -> ident_pkey == NULL ) { msyslog ( LOG_NOTICE , " " ) ; return ( XEVNT_ID ) ; } if ( ( dsa = EVP_PKEY_get0_DSA ( peer -> ident_pkey -> pkey ) ) == NULL ) { msyslog ( LOG_NOTICE , " " ) ; return ( XEVNT_PUB ) ; } if ( peer -> iffval != NULL ) BN_free ( peer -> iffval ) ; peer -> iffval = BN_new ( ) ; DSA_get0_pqg ( dsa , NULL , & q , NULL ) ; len = BN_num_bytes ( q ) ; BN_rand ( peer -> iffval , len * 8 , -1 , 1 ) ; bctx = BN_CTX_new ( ) ; BN_mod ( peer -> iffval , peer -> iffval , q , bctx ) ; BN_CTX_free ( bctx ) ; memset ( vp , 0 , sizeof ( struct value ) ) ; tstamp = crypto_time ( ) ; vp -> tstamp = htonl ( tstamp ) ; vp -> fstamp = htonl ( peer -> ident_pkey -> fstamp ) ; vp -> vallen = htonl ( len ) ; vp -> ptr = emalloc ( len ) ; BN_bn2bin ( peer -> iffval , vp -> ptr ) ; if ( tstamp == 0 ) return ( XEVNT_OK ) ; vp -> sig = emalloc ( sign_siglen ) ; ctx = EVP_MD_CTX_new ( ) ; EVP_SignInit ( ctx , sign_digest ) ; EVP_SignUpdate ( ctx , ( u_char * ) & vp -> tstamp , 12 ) ; EVP_SignUpdate ( ctx , vp -> ptr , len ) ; if ( EVP_SignFinal ( ctx , vp -> sig , & len , sign_pkey ) ) { INSIST ( len <= sign_siglen ) ; vp -> siglen = htonl ( len ) ; } EVP_MD_CTX_free ( ctx ) ; return ( XEVNT_OK ) ; }
The following routines implement the Schnorr (IFF) identity scheme
The following routines implement the Schnorr ( IFF ) identity scheme
/* peer pointer */ /* value pointer */ /* IFF parameters */ /* BIGNUM context */ /* signature context */ /*
	 * The identity parameters must have correct format and content.
	 */ /*
	 * Roll new random r (0 < r < q).
	 */ /* r mod q*/ /*
	 * Sign and send to Bob. The filestamp is from the local file.
	 */