You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by er...@apache.org on 2007/09/26 22:23:03 UTC

svn commit: r579785 - in /directory/sandbox/erodriguez/kerberos-pkinit/src: main/java/org/apache/directory/server/kerberos/pkinit/ test/java/org/apache/directory/server/kerberos/pkinit/

Author: erodriguez
Date: Wed Sep 26 13:23:03 2007
New Revision: 579785

URL: http://svn.apache.org/viewvc?rev=579785&view=rev
Log:
Client and server-side implementations for PKINIT's Diffie-Hellman (DH) mechanism:
o Client component using DH group and generating key using octetstring2key(x) function.
o  Server component using DH group and generating key using octetstring2key(x) function.
o  Test case demonstrating use of Oakley 1024-bit Modular Exponential (MODP) well-known group 2 [RFC2412].

Added:
    directory/sandbox/erodriguez/kerberos-pkinit/src/main/java/org/apache/directory/server/kerberos/pkinit/DhClient.java   (with props)
    directory/sandbox/erodriguez/kerberos-pkinit/src/main/java/org/apache/directory/server/kerberos/pkinit/DhServer.java   (with props)
    directory/sandbox/erodriguez/kerberos-pkinit/src/test/java/org/apache/directory/server/kerberos/pkinit/DhKeyAgreementTest.java   (with props)

Added: directory/sandbox/erodriguez/kerberos-pkinit/src/main/java/org/apache/directory/server/kerberos/pkinit/DhClient.java
URL: http://svn.apache.org/viewvc/directory/sandbox/erodriguez/kerberos-pkinit/src/main/java/org/apache/directory/server/kerberos/pkinit/DhClient.java?rev=579785&view=auto
==============================================================================
--- directory/sandbox/erodriguez/kerberos-pkinit/src/main/java/org/apache/directory/server/kerberos/pkinit/DhClient.java (added)
+++ directory/sandbox/erodriguez/kerberos-pkinit/src/main/java/org/apache/directory/server/kerberos/pkinit/DhClient.java Wed Sep 26 13:23:03 2007
@@ -0,0 +1,135 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.server.kerberos.pkinit;
+
+
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+
+/**
+ * The client-side of Diffie-Hellman key agreement for Kerberos PKINIT.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+class DhClient
+{
+    private static AlgorithmParameterSpec AES_IV = new IvParameterSpec( new byte[16] );
+
+    private KeyAgreement clientKeyAgree;
+    private SecretKey clientAesKey;
+
+
+    byte[] init( DHParameterSpec dhParamSpec ) throws Exception
+    {
+        // The client creates its own DH key pair, using the DH parameters from above.
+        KeyPairGenerator clientKpairGen = KeyPairGenerator.getInstance( "DH" );
+        clientKpairGen.initialize( dhParamSpec );
+        KeyPair clientKpair = clientKpairGen.generateKeyPair();
+
+        // The client creates and initializes its DH KeyAgreement object.
+        clientKeyAgree = KeyAgreement.getInstance( "DH" );
+        clientKeyAgree.init( clientKpair.getPrivate() );
+
+        // The client encodes its public key, and sends it over to the server.
+        return clientKpair.getPublic().getEncoded();
+    }
+
+
+    void doPhase( byte[] serverPubKeyEnc ) throws Exception
+    {
+        /*
+         * The client uses the server's public key for the first (and only) phase
+         * of its version of the DH protocol.  Before it can do so, it has to
+         * instantiate a DH public key from the server's encoded key material.
+         */
+        KeyFactory clientKeyFac = KeyFactory.getInstance( "DH" );
+        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec( serverPubKeyEnc );
+        PublicKey serverPubKey = clientKeyFac.generatePublic( x509KeySpec );
+
+        clientKeyAgree.doPhase( serverPubKey, true );
+    }
+
+
+    byte[] generateKey( byte[] clientDhNonce, byte[] serverDhNonce )
+    {
+        // ZZ length will be same as public key.
+        byte[] dhSharedSecret = clientKeyAgree.generateSecret();
+        byte[] x = dhSharedSecret;
+
+        if ( clientDhNonce != null && clientDhNonce.length > 0 )
+        {
+            x = concatenateBytes( dhSharedSecret, clientDhNonce );
+            x = concatenateBytes( dhSharedSecret, serverDhNonce );
+        }
+
+        byte[] secret = OctetString2Key.kTruncate( dhSharedSecret.length, x );
+        clientAesKey = new SecretKeySpec( secret, 0, 16, "AES" );
+
+        return clientAesKey.getEncoded();
+    }
+
+
+    /**
+     * Decrypt using AES in CTS mode.
+     * 
+     * @param cipherText
+     * @return
+     * @throws Exception
+     */
+    byte[] decryptAes( byte[] cipherText ) throws Exception
+    {
+        // Use the secret key to encrypt/decrypt data.
+        Cipher serverCipher = Cipher.getInstance( "AES/CTS/NoPadding" );
+        serverCipher.init( Cipher.DECRYPT_MODE, clientAesKey, AES_IV );
+
+        return serverCipher.doFinal( cipherText );
+    }
+
+
+    byte[] concatenateBytes( byte[] array1, byte[] array2 )
+    {
+        byte concatenatedBytes[] = new byte[array1.length + array2.length];
+
+        for ( int i = 0; i < array1.length; i++ )
+        {
+            concatenatedBytes[i] = array1[i];
+        }
+
+        for ( int j = array1.length; j < concatenatedBytes.length; j++ )
+        {
+            concatenatedBytes[j] = array2[j - array1.length];
+        }
+
+        return concatenatedBytes;
+    }
+}

Propchange: directory/sandbox/erodriguez/kerberos-pkinit/src/main/java/org/apache/directory/server/kerberos/pkinit/DhClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: directory/sandbox/erodriguez/kerberos-pkinit/src/main/java/org/apache/directory/server/kerberos/pkinit/DhServer.java
URL: http://svn.apache.org/viewvc/directory/sandbox/erodriguez/kerberos-pkinit/src/main/java/org/apache/directory/server/kerberos/pkinit/DhServer.java?rev=579785&view=auto
==============================================================================
--- directory/sandbox/erodriguez/kerberos-pkinit/src/main/java/org/apache/directory/server/kerberos/pkinit/DhServer.java (added)
+++ directory/sandbox/erodriguez/kerberos-pkinit/src/main/java/org/apache/directory/server/kerberos/pkinit/DhServer.java Wed Sep 26 13:23:03 2007
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.server.kerberos.pkinit;
+
+
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+
+/**
+ * The server-side of Diffie-Hellman key agreement for Kerberos PKINIT.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+class DhServer
+{
+    private static AlgorithmParameterSpec AES_IV = new IvParameterSpec( new byte[16] );
+
+    private KeyAgreement serverKeyAgree;
+    private SecretKey serverAesKey;
+
+
+    byte[] initAndDoPhase( byte[] clientPubKeyEnc ) throws Exception
+    {
+        /*
+         * The server has received the client's public key in encoded format.  The
+         * server instantiates a DH public key from the encoded key material.
+         */
+        KeyFactory serverKeyFac = KeyFactory.getInstance( "DH" );
+        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec( clientPubKeyEnc );
+        PublicKey clientPubKey = serverKeyFac.generatePublic( x509KeySpec );
+
+        /*
+         * The server gets the DH parameters associated with the client's public
+         * key.  The server must use the same parameters when it generates its own key pair.
+         */
+        DHParameterSpec dhParamSpec = ( ( DHPublicKey ) clientPubKey ).getParams();
+
+        // The server creates its own DH key pair.
+        KeyPairGenerator serverKpairGen = KeyPairGenerator.getInstance( "DH" );
+        serverKpairGen.initialize( dhParamSpec );
+        KeyPair serverKpair = serverKpairGen.generateKeyPair();
+
+        // The server creates and initializes its DH KeyAgreement object.
+        serverKeyAgree = KeyAgreement.getInstance( "DH" );
+        serverKeyAgree.init( serverKpair.getPrivate() );
+
+        /*
+         * The server uses the client's public key for the only phase of its
+         * side of the DH protocol.
+         */
+        serverKeyAgree.doPhase( clientPubKey, true );
+
+        // The server encodes its public key, and sends it over to the client.
+        return serverKpair.getPublic().getEncoded();
+    }
+
+
+    byte[] generateKey( byte[] clientDhNonce, byte[] serverDhNonce )
+    {
+        // ZZ length will be same as public key.
+        byte[] dhSharedSecret = serverKeyAgree.generateSecret();
+        byte[] x = dhSharedSecret;
+
+        if ( clientDhNonce != null && clientDhNonce.length > 0 )
+        {
+            x = concatenateBytes( dhSharedSecret, clientDhNonce );
+            x = concatenateBytes( dhSharedSecret, serverDhNonce );
+        }
+
+        byte[] secret = OctetString2Key.kTruncate( dhSharedSecret.length, x );
+        serverAesKey = new SecretKeySpec( secret, 0, 16, "AES" );
+
+        return serverAesKey.getEncoded();
+    }
+
+
+    /**
+     * Encrypt using AES in CTS mode.
+     *
+     * @param cleartext
+     * @return The cipher text.
+     * @throws Exception
+     */
+    byte[] encryptAes( byte[] clearText ) throws Exception
+    {
+        // Use the secret key to encrypt/decrypt data.
+        Cipher serverCipher = Cipher.getInstance( "AES/CTS/NoPadding" );
+        serverCipher.init( Cipher.ENCRYPT_MODE, serverAesKey, AES_IV );
+
+        return serverCipher.doFinal( clearText );
+    }
+
+
+    byte[] concatenateBytes( byte[] array1, byte[] array2 )
+    {
+        byte concatenatedBytes[] = new byte[array1.length + array2.length];
+
+        for ( int i = 0; i < array1.length; i++ )
+        {
+            concatenatedBytes[i] = array1[i];
+        }
+
+        for ( int j = array1.length; j < concatenatedBytes.length; j++ )
+        {
+            concatenatedBytes[j] = array2[j - array1.length];
+        }
+
+        return concatenatedBytes;
+    }
+}

Propchange: directory/sandbox/erodriguez/kerberos-pkinit/src/main/java/org/apache/directory/server/kerberos/pkinit/DhServer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: directory/sandbox/erodriguez/kerberos-pkinit/src/test/java/org/apache/directory/server/kerberos/pkinit/DhKeyAgreementTest.java
URL: http://svn.apache.org/viewvc/directory/sandbox/erodriguez/kerberos-pkinit/src/test/java/org/apache/directory/server/kerberos/pkinit/DhKeyAgreementTest.java?rev=579785&view=auto
==============================================================================
--- directory/sandbox/erodriguez/kerberos-pkinit/src/test/java/org/apache/directory/server/kerberos/pkinit/DhKeyAgreementTest.java (added)
+++ directory/sandbox/erodriguez/kerberos-pkinit/src/test/java/org/apache/directory/server/kerberos/pkinit/DhKeyAgreementTest.java Wed Sep 26 13:23:03 2007
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.server.kerberos.pkinit;
+
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests the Diffie-Hellman key agreement protocol between a client and server.
+ * 
+ * Generating a Secret Key Using the Diffie-Hellman Key Agreement Algorithm
+ * 
+ * Two parties use a key agreement protocol to generate identical secret keys for
+ * encryption without ever having to transmit the secret key. The protocol works
+ * by both parties agreeing on a set of values (a prime, a base, and a private
+ * value) which are used to generate a key pair.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class DhKeyAgreementTest extends TestCase
+{
+    /**
+     * Tests Diffie-Hellman using Oakley 1024-bit Modular Exponential (MODP)
+     * well-known group 2 [RFC2412].
+     * 
+     * @throws Exception
+     */
+    public void testPreGeneratedDhParams() throws Exception
+    {
+        DhClient client = new DhClient();
+        DhServer server = new DhServer();
+
+        byte[] clientPubKeyEnc = client.init( DhGroup.MODP_GROUP2 );
+        byte[] serverPubKeyEnc = server.initAndDoPhase( clientPubKeyEnc );
+
+        server.generateKey( null, null );
+
+        client.doPhase( serverPubKeyEnc );
+
+        client.generateKey( null, null );
+
+        byte[] clearText = "This is just an example".getBytes();
+
+        byte[] cipherText = server.encryptAes( clearText );
+        byte[] recovered = client.decryptAes( cipherText );
+
+        assertTrue( Arrays.equals( clearText, recovered ) );
+    }
+}

Propchange: directory/sandbox/erodriguez/kerberos-pkinit/src/test/java/org/apache/directory/server/kerberos/pkinit/DhKeyAgreementTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: directory/sandbox/erodriguez/kerberos-pkinit/src/test/java/org/apache/directory/server/kerberos/pkinit/DhKeyAgreementTest.java
------------------------------------------------------------------------------
    svn:executable = *