directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From plusplusjia...@apache.org
Subject [1/2] directory-kerby git commit: Add some code of the anonymous pkinit.
Date Fri, 27 Nov 2015 08:06:22 GMT
Repository: directory-kerby
Updated Branches:
  refs/heads/pkinit-support bdca83946 -> b9485672c


http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhClient.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhClient.java b/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhClient.java
new file mode 100644
index 0000000..207570a
--- /dev/null
+++ b/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhClient.java
@@ -0,0 +1,128 @@
+/*
+ *  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.kerby.kerberos.kerb.crypto.dh;
+
+import org.apache.kerby.kerberos.kerb.crypto.EncTypeHandler;
+import org.apache.kerby.kerberos.kerb.crypto.EncryptionHandler;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionType;
+import org.apache.kerby.kerberos.kerb.spec.base.KeyUsage;
+
+import javax.crypto.KeyAgreement;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+import java.security.spec.X509EncodedKeySpec;
+
+
+/**
+ * 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$
+ */
+public class DhClient {
+
+    private KeyAgreement clientKeyAgree;
+    private EncryptionKey clientKey;
+    private DHParameterSpec dhParameterSpec;
+
+
+    public DHParameterSpec getDhParam() {
+        return dhParameterSpec;
+    }
+
+    public DHPublicKey init(DHParameterSpec dhParamSpec) throws Exception {
+        dhParameterSpec = dhParamSpec;
+        // 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 (DHPublicKey) clientKpair.getPublic();
+    }
+
+
+    public 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);
+    }
+
+    public EncryptionKey generateKey(byte[] clientDhNonce, byte[] serverDhNonce, EncryptionType type) {
+        // ZZ length will be same as public key.
+        byte[] dhSharedSecret = clientKeyAgree.generateSecret();
+        byte[] x = dhSharedSecret;
+
+        if (clientDhNonce != null && clientDhNonce.length > 0
+                && serverDhNonce != null && serverDhNonce.length > 0) {
+            x = concatenateBytes(dhSharedSecret, clientDhNonce);
+            x = concatenateBytes(x, serverDhNonce);
+        }
+
+        byte[] secret = OctetString2Key.kTruncate(dhSharedSecret.length, x);
+
+        clientKey = new EncryptionKey(type, secret);
+
+        return clientKey;
+    }
+
+    /**
+     * Decrypt
+     *
+     * @param cipherText
+     * @return
+     * @throws Exception
+     */
+    public byte[] decrypt(byte[] cipherText, KeyUsage usage) throws Exception {
+        // Use the secret key to encrypt/decrypt data.
+        EncTypeHandler encType = EncryptionHandler.getEncHandler(clientKey.getKeyType());
+        return encType.decrypt(cipherText, clientKey.getKeyData(), usage.getIntValue());
+    }
+
+    private 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;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhGroup.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhGroup.java b/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhGroup.java
new file mode 100644
index 0000000..ba92589
--- /dev/null
+++ b/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhGroup.java
@@ -0,0 +1,138 @@
+/*
+ *  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.kerby.kerberos.kerb.crypto.dh;
+
+
+import javax.crypto.spec.DHParameterSpec;
+import java.math.BigInteger;
+
+
+/**
+ * "When using the Diffie-Hellman key agreement method, implementations MUST
+ * support Oakley 1024-bit Modular Exponential (MODP) well-known group 2
+ * [RFC2412] and Oakley 2048-bit MODP well-known group 14 [RFC3526] and
+ * SHOULD support Oakley 4096-bit MODP well-known group 16 [RFC3526]."
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class DhGroup {
+    /**
+     * From:
+     * The OAKLEY Key Determination Protocol
+     * http://www.ietf.org/rfc/rfc2412.txt
+     * <p/>
+     * Well-Known Group 2:  A 1024 bit prime
+     * This group is assigned id 2 (two).
+     * The prime is 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }.
+     * The generator is 2 (decimal)
+     */
+    public static final DHParameterSpec MODP_GROUP2;
+
+    static {
+        StringBuffer sb = new StringBuffer();
+        sb.append("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1");
+        sb.append("29024E088A67CC74020BBEA63B139B22514A08798E3404DD");
+        sb.append("EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245");
+        sb.append("E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED");
+        sb.append("EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381");
+        sb.append("FFFFFFFFFFFFFFFF");
+
+        BigInteger prime = new BigInteger(sb.toString(), 16);
+        BigInteger generator = BigInteger.valueOf(2);
+
+        MODP_GROUP2 = new DHParameterSpec(prime, generator);
+    }
+
+    /**
+     * From:
+     * More Modular Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange (IKE)
+     * http://www.ietf.org/rfc/rfc3526.txt
+     * <p/>
+     * 2048-bit MODP Group
+     * This group is assigned id 14.
+     * This prime is: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }
+     * The generator is: 2.
+     */
+    public static final DHParameterSpec MODP_GROUP14;
+
+    static {
+        StringBuffer sb = new StringBuffer();
+        sb.append("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1");
+        sb.append("29024E088A67CC74020BBEA63B139B22514A08798E3404DD");
+        sb.append("EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245");
+        sb.append("E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED");
+        sb.append("EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D");
+        sb.append("C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F");
+        sb.append("83655D23DCA3AD961C62F356208552BB9ED529077096966D");
+        sb.append("670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B");
+        sb.append("E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9");
+        sb.append("DE2BCBF6955817183995497CEA956AE515D2261898FA0510");
+        sb.append("15728E5A8AACAA68FFFFFFFFFFFFFFFF");
+
+        BigInteger prime = new BigInteger(sb.toString(), 16);
+        BigInteger generator = BigInteger.valueOf(2);
+
+        MODP_GROUP14 = new DHParameterSpec(prime, generator);
+    }
+
+    /**
+     * From:
+     * More Modular Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange (IKE)
+     * http://www.ietf.org/rfc/rfc3526.txt
+     * <p/>
+     * 4096-bit MODP Group
+     * This group is assigned id 16.
+     * This prime is: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }
+     * The generator is: 2.
+     */
+    public static final DHParameterSpec MODP_GROUP16;
+
+    static {
+        StringBuffer sb = new StringBuffer();
+        sb.append("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1");
+        sb.append("29024E088A67CC74020BBEA63B139B22514A08798E3404DD");
+        sb.append("EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245");
+        sb.append("E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED");
+        sb.append("EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D");
+        sb.append("C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F");
+        sb.append("83655D23DCA3AD961C62F356208552BB9ED529077096966D");
+        sb.append("670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B");
+        sb.append("E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9");
+        sb.append("DE2BCBF6955817183995497CEA956AE515D2261898FA0510");
+        sb.append("15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64");
+        sb.append("ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7");
+        sb.append("ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B");
+        sb.append("F12FFA06D98A0864D87602733EC86A64521F2B18177B200C");
+        sb.append("BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31");
+        sb.append("43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7");
+        sb.append("88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA");
+        sb.append("2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6");
+        sb.append("287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED");
+        sb.append("1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9");
+        sb.append("93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199");
+        sb.append("FFFFFFFFFFFFFFFF");
+
+        BigInteger prime = new BigInteger(sb.toString(), 16);
+        BigInteger generator = BigInteger.valueOf(2);
+
+        MODP_GROUP16 = new DHParameterSpec(prime, generator);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhServer.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhServer.java b/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhServer.java
new file mode 100644
index 0000000..3104da7
--- /dev/null
+++ b/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhServer.java
@@ -0,0 +1,126 @@
+/*
+ *  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.kerby.kerberos.kerb.crypto.dh;
+
+import org.apache.kerby.kerberos.kerb.crypto.EncTypeHandler;
+import org.apache.kerby.kerberos.kerb.crypto.EncryptionHandler;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionType;
+import org.apache.kerby.kerberos.kerb.spec.base.KeyUsage;
+
+import javax.crypto.KeyAgreement;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+import java.security.spec.X509EncodedKeySpec;
+
+
+/**
+ * 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$
+ */
+public class DhServer {
+
+    private KeyAgreement serverKeyAgree;
+    private EncryptionKey serverKey;
+
+    public PublicKey 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();
+    }
+
+    public EncryptionKey generateKey(byte[] clientDhNonce, byte[] serverDhNonce, EncryptionType type) {
+        // ZZ length will be same as public key.
+        byte[] dhSharedSecret = serverKeyAgree.generateSecret();
+        byte[] x = dhSharedSecret;
+
+        if (clientDhNonce != null && clientDhNonce.length > 0
+                && serverDhNonce != null && serverDhNonce.length > 0) {
+            x = concatenateBytes(dhSharedSecret, clientDhNonce);
+            x = concatenateBytes(x, serverDhNonce);
+        }
+
+        byte[] secret = OctetString2Key.kTruncate(dhSharedSecret.length, x);
+        serverKey = new EncryptionKey(type, secret);
+
+        return serverKey;
+    }
+
+    /**
+     * Encrypt
+     *
+     * @param clearText
+     * @return The cipher text.
+     * @throws Exception
+     */
+    public byte[] encrypt(byte[] clearText, KeyUsage usage) throws Exception {
+        // Use the secret key to encrypt/decrypt data.
+        EncTypeHandler encType = EncryptionHandler.getEncHandler(serverKey.getKeyType());
+        return encType.decrypt(clearText, serverKey.getKeyData(), usage.getIntValue());
+    }
+
+    private 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;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/OctetString2Key.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/OctetString2Key.java b/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/OctetString2Key.java
new file mode 100644
index 0000000..32715ff
--- /dev/null
+++ b/kerby-kerb/kerb-crypto/src/main/java/org/apache/kerby/kerberos/kerb/crypto/dh/OctetString2Key.java
@@ -0,0 +1,91 @@
+/*
+ *  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.kerby.kerberos.kerb.crypto.dh;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * From RFC 4556:
+ * <p/>
+ * Define the function octetstring2key() as follows:
+ * <p/>
+ * octetstring2key(x) == random-to-key(K-truncate(
+ * SHA1(0x00 | x) |
+ * SHA1(0x01 | x) |
+ * SHA1(0x02 | x) |
+ * ...
+ * ))
+ * <p/>
+ * where x is an octet string; | is the concatenation operator; 0x00,
+ * 0x01, 0x02, etc. are each represented as a single octet; random-
+ * to-key() is an operation that generates a protocol key from a
+ * bitstring of length K; and K-truncate truncates its input to the
+ * first K bits.  Both K and random-to-key() are as defined in the
+ * kcrypto profile [RFC3961] for the enctype of the AS reply key.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class OctetString2Key {
+    /**
+     * Performs the function K-truncate to generate the AS reply key k.
+     *
+     * @param k
+     * @param x
+     * @return The AS reply key value.
+     */
+    public static byte[] kTruncate(int k, byte[] x) {
+        int numberOfBytes = k / 8;
+        byte[] result = new byte[numberOfBytes];
+
+        int count = 0;
+        byte[] filler = calculateIntegrity((byte) count, x);
+
+        int position = 0;
+
+        for (int i = 0; i < numberOfBytes; i++) {
+            if (position < filler.length) {
+                result[i] = filler[position];
+                position++;
+            } else {
+                count++;
+                filler = calculateIntegrity((byte) count, x);
+                position = 0;
+                result[i] = filler[position];
+                position++;
+            }
+        }
+
+        return result;
+    }
+
+
+    private static byte[] calculateIntegrity(byte count, byte[] data) {
+        try {
+            MessageDigest digester = MessageDigest.getInstance("SHA1");
+            digester.update(count);
+
+            return digester.digest(data);
+        } catch (NoSuchAlgorithmException nsae) {
+            return new byte[0];
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-crypto/src/test/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhGroupTest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-crypto/src/test/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhGroupTest.java b/kerby-kerb/kerb-crypto/src/test/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhGroupTest.java
new file mode 100644
index 0000000..3061bb8
--- /dev/null
+++ b/kerby-kerb/kerb-crypto/src/test/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhGroupTest.java
@@ -0,0 +1,53 @@
+/*
+ *  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.kerby.kerberos.kerb.crypto.dh;
+
+import junit.framework.TestCase;
+import org.apache.kerby.kerberos.kerb.crypto.dh.DhGroup;
+
+/**
+ * "When using the Diffie-Hellman key agreement method, implementations MUST
+ * support Oakley 1024-bit Modular Exponential (MODP) well-known group 2
+ * [RFC2412] and Oakley 2048-bit MODP well-known group 14 [RFC3526] and
+ * SHOULD support Oakley 4096-bit MODP well-known group 16 [RFC3526]."
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class DhGroupTest extends TestCase {
+    /**
+     * Tests that the translation of the hex representation of the prime modulus
+     * resulted in the expected bit length.
+     */
+    public void testPrimeBitLengths() {
+        TestCase.assertEquals(1024, DhGroup.MODP_GROUP2.getP().bitLength());
+        TestCase.assertEquals(2048, DhGroup.MODP_GROUP14.getP().bitLength());
+        TestCase.assertEquals(4096, DhGroup.MODP_GROUP16.getP().bitLength());
+    }
+
+    /**
+     * Tests the generator values.
+     */
+    public void testGeneratorValues() {
+        TestCase.assertEquals(2, DhGroup.MODP_GROUP2.getG().intValue());
+        TestCase.assertEquals(2, DhGroup.MODP_GROUP14.getG().intValue());
+        TestCase.assertEquals(2, DhGroup.MODP_GROUP16.getG().intValue());
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-crypto/src/test/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhKeyAgreementTest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-crypto/src/test/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhKeyAgreementTest.java b/kerby-kerb/kerb-crypto/src/test/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhKeyAgreementTest.java
new file mode 100644
index 0000000..519faaa
--- /dev/null
+++ b/kerby-kerb/kerb-crypto/src/test/java/org/apache/kerby/kerberos/kerb/crypto/dh/DhKeyAgreementTest.java
@@ -0,0 +1,172 @@
+/*
+ *  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.kerby.kerberos.kerb.crypto.dh;
+
+
+import junit.framework.TestCase;
+import org.apache.kerby.kerberos.kerb.crypto.dh.DhClient;
+import org.apache.kerby.kerberos.kerb.crypto.dh.DhGroup;
+import org.apache.kerby.kerberos.kerb.crypto.dh.DhServer;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionType;
+import org.apache.kerby.kerberos.kerb.spec.base.KeyUsage;
+
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
+
+
+/**
+ * Tests the Diffie-Hellman key agreement protocol between a client and server.
+ * <p/>
+ * Generating a Secret Key Using the Diffie-Hellman Key Agreement Algorithm
+ * <p/>
+ * 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 {
+    private static SecureRandom secureRandom = new SecureRandom();
+
+    /**
+     * 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).getEncoded();
+        byte[] serverPubKeyEnc = server.initAndDoPhase(clientPubKeyEnc).getEncoded();
+
+        server.generateKey(null, null, EncryptionType.AES128_CTS_HMAC_SHA1_96);
+
+        client.doPhase(serverPubKeyEnc);
+
+        client.generateKey(null, null, EncryptionType.AES128_CTS_HMAC_SHA1_96);
+
+        byte[] clearText = "This is just an example".getBytes();
+
+        byte[] cipherText = server.encrypt(clearText, KeyUsage.UNKNOWN);
+        byte[] recovered = client.decrypt(cipherText, KeyUsage.UNKNOWN);
+
+        assertTrue(Arrays.equals(clearText, recovered));
+    }
+
+
+    /**
+     * Tests Diffie-Hellman using Oakley 1024-bit Modular Exponential (MODP)
+     * well-known group 2 [RFC2412], including the optional DH nonce.
+     * <p/>
+     * "This nonce string MUST be as long as the longest key length of the symmetric
+     * key types that the client supports.  This nonce MUST be chosen randomly."
+     *
+     * @throws Exception
+     */
+    public void testPreGeneratedDhParamsWithNonce() throws Exception {
+        byte[] clientDhNonce = new byte[16];
+        secureRandom.nextBytes(clientDhNonce);
+
+        byte[] serverDhNonce = new byte[16];
+        secureRandom.nextBytes(serverDhNonce);
+
+        DhClient client = new DhClient();
+        DhServer server = new DhServer();
+
+        byte[] clientPubKeyEnc = client.init(DhGroup.MODP_GROUP2).getEncoded();
+        byte[] serverPubKeyEnc = server.initAndDoPhase(clientPubKeyEnc).getEncoded();
+
+        server.generateKey(clientDhNonce, serverDhNonce, EncryptionType.AES128_CTS_HMAC_SHA1_96);
+
+        client.doPhase(serverPubKeyEnc);
+
+        client.generateKey(clientDhNonce, serverDhNonce, EncryptionType.AES128_CTS_HMAC_SHA1_96);
+
+        byte[] clearText = "This is just an example".getBytes();
+
+        byte[] cipherText = server.encrypt(clearText, KeyUsage.UNKNOWN);
+        byte[] recovered = client.decrypt(cipherText, KeyUsage.UNKNOWN);
+
+        assertTrue(Arrays.equals(clearText, recovered));
+    }
+
+
+    /**
+     * Tests Diffie-Hellman using Oakley 1024-bit Modular Exponential (MODP)
+     * well-known group 2 [RFC2412].
+     *
+     * @throws Exception
+     */
+    public void testGeneratedDhParams() throws Exception {
+        DhClient client = new DhClient();
+        DhServer server = new DhServer();
+
+        DHPublicKey clientPubKey = client.init(DhGroup.MODP_GROUP14);
+        DHParameterSpec spec = clientPubKey.getParams();
+
+        BigInteger y = clientPubKey.getY();
+        BigInteger p = spec.getP();
+        BigInteger g = spec.getG();
+        DHPublicKeySpec dhPublicKeySpec = new DHPublicKeySpec(y, p, g);
+
+        KeyFactory keyFactory = null;
+        try {
+            keyFactory = KeyFactory.getInstance("DH");
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        DHPublicKey dhPublicKey = null;
+        try {
+            dhPublicKey = (DHPublicKey) keyFactory.generatePublic(dhPublicKeySpec);
+        } catch (InvalidKeySpecException e) {
+            e.printStackTrace();
+        }
+
+        byte[] serverPubKeyEnc = null;
+        try {
+            serverPubKeyEnc = server.initAndDoPhase(dhPublicKey.getEncoded()).getEncoded();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        server.generateKey(null, null, EncryptionType.AES128_CTS_HMAC_SHA1_96);
+
+        client.doPhase(serverPubKeyEnc);
+
+        client.generateKey(null, null, EncryptionType.AES128_CTS_HMAC_SHA1_96);
+
+        byte[] clearText = "This is just an example".getBytes();
+
+        byte[] cipherText = server.encrypt(clearText, KeyUsage.UNKNOWN);
+        byte[] recovered = client.decrypt(cipherText, KeyUsage.UNKNOWN);
+
+        assertTrue(Arrays.equals(clearText, recovered));
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-crypto/src/test/java/org/apache/kerby/kerberos/kerb/crypto/dh/OctetString2KeyTest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-crypto/src/test/java/org/apache/kerby/kerberos/kerb/crypto/dh/OctetString2KeyTest.java b/kerby-kerb/kerb-crypto/src/test/java/org/apache/kerby/kerberos/kerb/crypto/dh/OctetString2KeyTest.java
new file mode 100644
index 0000000..b1dca2d
--- /dev/null
+++ b/kerby-kerb/kerb-crypto/src/test/java/org/apache/kerby/kerberos/kerb/crypto/dh/OctetString2KeyTest.java
@@ -0,0 +1,225 @@
+/*
+ *  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.kerby.kerberos.kerb.crypto.dh;
+
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+
+
+/**
+ * From RFC 4556:
+ * <p/>
+ * "Appendix B.  Test Vectors
+ * <p/>
+ * Function octetstring2key() is defined in Section 3.2.3.1.  This section describes
+ * a few sets of test vectors that would be useful for implementers of octetstring2key()."
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class OctetString2KeyTest extends TestCase {
+    /**
+     * Set 1:
+     * =====
+     * Input octet string x is:
+     * <p/>
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * <p/>
+     * Output of K-truncate() when the key size is 32 octets:
+     * <p/>
+     * 5e e5 0d 67 5c 80 9f e5 9e 4a 77 62 c5 4b 65 83
+     * 75 47 ea fb 15 9b d8 cd c7 5f fc a5 91 1e 4c 41
+     */
+    public void testSet1() {
+        byte[] inputOctetString = new byte[16 * 16];
+
+        byte[] expectedOutput =
+                {(byte) 0x5e, (byte) 0xe5, (byte) 0x0d, (byte) 0x67, (byte) 0x5c, (byte) 0x80, (byte) 0x9f,
+                        (byte) 0xe5, (byte) 0x9e, (byte) 0x4a, (byte) 0x77, (byte) 0x62, (byte) 0xc5,
+                        (byte) 0x4b, (byte) 0x65, (byte) 0x83, (byte) 0x75, (byte) 0x47, (byte) 0xea,
+                        (byte) 0xfb, (byte) 0x15, (byte) 0x9b, (byte) 0xd8, (byte) 0xcd, (byte) 0xc7,
+                        (byte) 0x5f, (byte) 0xfc, (byte) 0xa5, (byte) 0x91, (byte) 0x1e, (byte) 0x4c, (byte) 0x41};
+
+        int keySize = 32 * 8;
+
+        byte[] result = OctetString2Key.kTruncate(keySize, inputOctetString);
+
+        assertTrue(Arrays.equals(result, expectedOutput));
+    }
+
+
+    /**
+     * Set 2:
+     * =====
+     * Input octet string x is:
+     * <p/>
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+     * <p/>
+     * Output of K-truncate() when the key size is 32 octets:
+     * <p/>
+     * ac f7 70 7c 08 97 3d df db 27 cd 36 14 42 cc fb
+     * a3 55 c8 88 4c b4 72 f3 7d a6 36 d0 7d 56 78 7e
+     */
+    public void testSet2() {
+        byte[] inputOctetString = new byte[16 * 8];
+
+        byte[] expectedOutput =
+                {(byte) 0xac, (byte) 0xf7, (byte) 0x70, (byte) 0x7c, (byte) 0x08, (byte) 0x97, (byte) 0x3d,
+                        (byte) 0xdf, (byte) 0xdb, (byte) 0x27, (byte) 0xcd, (byte) 0x36, (byte) 0x14,
+                        (byte) 0x42, (byte) 0xcc, (byte) 0xfb, (byte) 0xa3, (byte) 0x55, (byte) 0xc8,
+                        (byte) 0x88, (byte) 0x4c, (byte) 0xb4, (byte) 0x72, (byte) 0xf3, (byte) 0x7d,
+                        (byte) 0xa6, (byte) 0x36, (byte) 0xd0, (byte) 0x7d, (byte) 0x56, (byte) 0x78, (byte) 0x7e};
+
+        int keySize = 32 * 8;
+
+        byte[] result = OctetString2Key.kTruncate(keySize, inputOctetString);
+
+        assertTrue(Arrays.equals(result, expectedOutput));
+    }
+
+
+    /**
+     * Set 3:
+     * ======
+     * Input octet string x is:
+     * <p/>
+     * 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
+     * 10 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e
+     * 0f 10 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d
+     * 0e 0f 10 00 01 02 03 04 05 06 07 08 09 0a 0b 0c
+     * 0d 0e 0f 10 00 01 02 03 04 05 06 07 08 09 0a 0b
+     * 0c 0d 0e 0f 10 00 01 02 03 04 05 06 07 08 09 0a
+     * 0b 0c 0d 0e 0f 10 00 01 02 03 04 05 06 07 08 09
+     * 0a 0b 0c 0d 0e 0f 10 00 01 02 03 04 05 06 07 08
+     * <p/>
+     * Output of K-truncate() when the key size is 32 octets:
+     * <p/>
+     * c4 42 da 58 5f cb 80 e4 3b 47 94 6f 25 40 93 e3
+     * 73 29 d9 90 01 38 0d b7 83 71 db 3a cf 5c 79 7e
+     */
+    public void testSet3() {
+        byte[] inputOctetString =
+                {(byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06,
+                        (byte) 0x07, (byte) 0x08, (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c,
+                        (byte) 0x0d, (byte) 0x0e, (byte) 0x0f, (byte) 0x10, (byte) 0x00, (byte) 0x01,
+                        (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
+                        (byte) 0x08, (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c, (byte) 0x0d,
+                        (byte) 0x0e, (byte) 0x0f, (byte) 0x10, (byte) 0x00, (byte) 0x01, (byte) 0x02,
+                        (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08,
+                        (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c, (byte) 0x0d, (byte) 0x0e,
+                        (byte) 0x0f, (byte) 0x10, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03,
+                        (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08, (byte) 0x09,
+                        (byte) 0x0a, (byte) 0x0b, (byte) 0x0c, (byte) 0x0d, (byte) 0x0e, (byte) 0x0f,
+                        (byte) 0x10, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+                        (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08, (byte) 0x09, (byte) 0x0a,
+                        (byte) 0x0b, (byte) 0x0c, (byte) 0x0d, (byte) 0x0e, (byte) 0x0f, (byte) 0x10,
+                        (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05,
+                        (byte) 0x06, (byte) 0x07, (byte) 0x08, (byte) 0x09, (byte) 0x0a, (byte) 0x0b,
+                        (byte) 0x0c, (byte) 0x0d, (byte) 0x0e, (byte) 0x0f, (byte) 0x10, (byte) 0x00,
+                        (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06,
+                        (byte) 0x07, (byte) 0x08, (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c,
+                        (byte) 0x0d, (byte) 0x0e, (byte) 0x0f, (byte) 0x10, (byte) 0x00, (byte) 0x01,
+                        (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08};
+
+        byte[] expectedOutput =
+                {(byte) 0xc4, (byte) 0x42, (byte) 0xda, (byte) 0x58, (byte) 0x5f, (byte) 0xcb, (byte) 0x80,
+                        (byte) 0xe4, (byte) 0x3b, (byte) 0x47, (byte) 0x94, (byte) 0x6f, (byte) 0x25,
+                        (byte) 0x40, (byte) 0x93, (byte) 0xe3, (byte) 0x73, (byte) 0x29, (byte) 0xd9,
+                        (byte) 0x90, (byte) 0x01, (byte) 0x38, (byte) 0x0d, (byte) 0xb7, (byte) 0x83,
+                        (byte) 0x71, (byte) 0xdb, (byte) 0x3a, (byte) 0xcf, (byte) 0x5c, (byte) 0x79, (byte) 0x7e};
+
+        int keySize = 32 * 8;
+
+        byte[] result = OctetString2Key.kTruncate(keySize, inputOctetString);
+
+        assertTrue(Arrays.equals(result, expectedOutput));
+    }
+
+
+    /**
+     * Set 4:
+     * =====
+     * Input octet string x is:
+     * <p/>
+     * 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
+     * 10 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e
+     * 0f 10 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d
+     * 0e 0f 10 00 01 02 03 04 05 06 07 08 09 0a 0b 0c
+     * 0d 0e 0f 10 00 01 02 03 04 05 06 07 08
+     * <p/>
+     * Output of K-truncate() when the key size is 32 octets:
+     * <p/>
+     * 00 53 95 3b 84 c8 96 f4 eb 38 5c 3f 2e 75 1c 4a
+     * 59 0e d6 ff ad ca 6f f6 4f 47 eb eb 8d 78 0f fc
+     */
+    public void testSet4() {
+        byte[] inputOctetString =
+                {(byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06,
+                        (byte) 0x07, (byte) 0x08, (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c,
+                        (byte) 0x0d, (byte) 0x0e, (byte) 0x0f, (byte) 0x10, (byte) 0x00, (byte) 0x01,
+                        (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
+                        (byte) 0x08, (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c, (byte) 0x0d,
+                        (byte) 0x0e, (byte) 0x0f, (byte) 0x10, (byte) 0x00, (byte) 0x01, (byte) 0x02,
+                        (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08,
+                        (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c, (byte) 0x0d, (byte) 0x0e,
+                        (byte) 0x0f, (byte) 0x10, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03,
+                        (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08, (byte) 0x09,
+                        (byte) 0x0a, (byte) 0x0b, (byte) 0x0c, (byte) 0x0d, (byte) 0x0e, (byte) 0x0f,
+                        (byte) 0x10, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+                        (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08};
+
+        byte[] expectedOutput =
+                {(byte) 0x00, (byte) 0x53, (byte) 0x95, (byte) 0x3b, (byte) 0x84, (byte) 0xc8, (byte) 0x96,
+                        (byte) 0xf4, (byte) 0xeb, (byte) 0x38, (byte) 0x5c, (byte) 0x3f, (byte) 0x2e,
+                        (byte) 0x75, (byte) 0x1c, (byte) 0x4a, (byte) 0x59, (byte) 0x0e, (byte) 0xd6,
+                        (byte) 0xff, (byte) 0xad, (byte) 0xca, (byte) 0x6f, (byte) 0xf6, (byte) 0x4f,
+                        (byte) 0x47, (byte) 0xeb, (byte) 0xeb, (byte) 0x8d, (byte) 0x78, (byte) 0x0f, (byte) 0xfc};
+
+        int keySize = 32 * 8;
+
+        byte[] result = OctetString2Key.kTruncate(keySize, inputOctetString);
+
+        assertTrue(Arrays.equals(result, expectedOutput));
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-server/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/pom.xml b/kerby-kerb/kerb-server/pom.xml
index edb355c..ddea681 100644
--- a/kerby-kerb/kerb-server/pom.xml
+++ b/kerby-kerb/kerb-server/pom.xml
@@ -47,5 +47,10 @@
       <artifactId>kerb-identity</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>not-yet-commons-ssl</artifactId>
+      <version>${project.version}</version>
+    </dependency>
   </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/Asn1InputBuffer.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/Asn1InputBuffer.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/Asn1InputBuffer.java
new file mode 100644
index 0000000..ce52b52
--- /dev/null
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/Asn1InputBuffer.java
@@ -0,0 +1,129 @@
+/**
+ *  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.kerby.kerberos.kerb.server;
+
+import org.apache.kerby.asn1.LimitedByteBuffer;
+import org.apache.kerby.asn1.type.AbstractAsn1Type;
+import org.apache.kerby.asn1.type.Asn1Item;
+import org.apache.kerby.asn1.type.Asn1Type;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Asn1 decoder. Given an input stream, it validates and parses
+ * according to ASN1 spec, and the resultant object can be read
+ * and read until exhausted.
+ */
+public class Asn1InputBuffer {
+    private final LimitedByteBuffer limitedBuffer;
+
+    /**
+     * Constructor with bytes.
+     * @param bytes The bytes
+     */
+    public Asn1InputBuffer(byte[] bytes) {
+        this(new LimitedByteBuffer(bytes));
+    }
+
+    /**
+     * Constructor with a ByteBuffer.
+     * @param byteBuffer The byte buffer
+     */
+    public Asn1InputBuffer(ByteBuffer byteBuffer) {
+        this(new LimitedByteBuffer(byteBuffer));
+    }
+
+    /**
+     * Constructor with LimitedByteBuffer.
+     * @param limitedByteBuffer The limited byte buffer
+     */
+    public Asn1InputBuffer(LimitedByteBuffer limitedByteBuffer) {
+        this.limitedBuffer = limitedByteBuffer;
+    }
+
+    /**
+     * Parse and read ASN1 object from the stream. If it's already
+     * exhausted then null will be returned to indicate the end.
+     * @return an ASN1 object if available otherwise null
+     * @throws IOException e
+     */
+    public Asn1Type read() throws IOException {
+        if (!limitedBuffer.available()) {
+            return null;
+        }
+        Asn1Item one = decodeOne(limitedBuffer);
+        if (one.isSimple()) {
+            one.decodeValueAsSimple();
+        } else if (one.isCollection()) {
+            one.decodeValueAsCollection();
+        }
+        if (one.isFullyDecoded()) {
+            return one.getValue();
+        }
+        return one;
+    }
+
+    public static Asn1Item decodeOne(LimitedByteBuffer content) throws IOException {
+        int tag = AbstractAsn1Type.readTag(content);
+        int tagNo = AbstractAsn1Type.readTagNo(content, tag);
+        int length = AbstractAsn1Type.readLength(content);
+        if (length < 0) {
+            throw new IOException("Unexpected length");
+        }
+        LimitedByteBuffer valueContent = new LimitedByteBuffer(content, length);
+//        content.skip(length);
+
+        Asn1Item result = new Asn1Item(tag, tagNo, valueContent);
+        if(!result.isCollection() && !result.isAppSpecific()) {
+            content.skip(length);
+        }
+        if (result.isSimple()) {
+            result.decodeValueAsSimple();
+        }
+        return result;
+    }
+
+    /**
+     * Read from bytes.
+     *
+     * @param bytes The bytes
+     * @throws IOException e
+     */
+    public void readBytes(byte[] bytes) throws IOException {
+        limitedBuffer.readBytes(bytes);
+    }
+
+    public byte[] readAllLeftBytes() throws IOException {
+        return limitedBuffer.readAllLeftBytes();
+    }
+
+    public void skipNext() throws IOException {
+        if (limitedBuffer.available()) {
+            AbstractAsn1Type.skipOne(limitedBuffer);
+        }
+    }
+
+    public void skipBytes(int len) throws IOException {
+        if (limitedBuffer.available()) {
+            limitedBuffer.skip(len);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcHandler.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcHandler.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcHandler.java
index eb63a13..ad35b71 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcHandler.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcHandler.java
@@ -19,6 +19,8 @@
  */
 package org.apache.kerby.kerberos.kerb.server;
 
+import org.apache.kerby.asn1.type.Asn1Item;
+import org.apache.kerby.asn1.type.Asn1Type;
 import org.apache.kerby.kerberos.kerb.KrbCodec;
 import org.apache.kerby.kerberos.kerb.KrbErrorCode;
 import org.apache.kerby.kerberos.kerb.KrbException;
@@ -71,6 +73,31 @@ public class KdcHandler {
         KdcRequest kdcRequest = null;
         KrbMessage krbResponse;
 
+        ByteBuffer message = receivedMessage.duplicate();
+        Asn1InputBuffer ib = new Asn1InputBuffer(message);
+        Asn1Type body = null;
+        Asn1Type fd = null;
+        try {
+            fd = ib.read();
+            body = fd;
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        while (fd != null) {
+            body = fd;
+            try {
+                fd = ib.read();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        byte[] reqBodyBytes = null;
+        try {
+            reqBodyBytes = ((Asn1Item)body).getBodyContent().readAllLeftBytes();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
         try {
             krbRequest = KrbCodec.decodeMessage(receivedMessage);
         } catch (IOException e) {
@@ -98,6 +125,9 @@ public class KdcHandler {
             }
         }
 
+        // For checksum
+        kdcRequest.setReqBodyBytes(reqBodyBytes);
+
         if (remoteAddress == null) {
             throw new KrbException("Remote address is null, not available.");
         }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/DhServer.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/DhServer.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/DhServer.java
deleted file mode 100644
index d8bf903..0000000
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/DhServer.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- *  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.kerby.kerberos.kerb.server.preauth.pkinit;
-
-
-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;
-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;
-
-
-/**
- * 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 aesIv = new IvParameterSpec(new byte[16]);
-
-    private KeyAgreement serverKeyAgree;
-    private SecretKey serverAesKey;
-
-
-    PublicKey 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();
-    }
-
-
-    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
-                && serverDhNonce != null && serverDhNonce.length > 0) {
-            x = concatenateBytes(dhSharedSecret, clientDhNonce);
-            x = concatenateBytes(x, 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, aesIv);
-
-        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;
-    }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/OctetString2Key.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/OctetString2Key.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/OctetString2Key.java
deleted file mode 100644
index 9829642..0000000
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/OctetString2Key.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- *  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.kerby.kerberos.kerb.server.preauth.pkinit;
-
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-
-/**
- * From RFC 4556:
- * <p/>
- * Define the function octetstring2key() as follows:
- * <p/>
- * octetstring2key(x) == random-to-key(K-truncate(
- * SHA1(0x00 | x) |
- * SHA1(0x01 | x) |
- * SHA1(0x02 | x) |
- * ...
- * ))
- * <p/>
- * where x is an octet string; | is the concatenation operator; 0x00,
- * 0x01, 0x02, etc. are each represented as a single octet; random-
- * to-key() is an operation that generates a protocol key from a
- * bitstring of length K; and K-truncate truncates its input to the
- * first K bits.  Both K and random-to-key() are as defined in the
- * kcrypto profile [RFC3961] for the enctype of the AS reply key.
- *
- * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- * @version $Rev$, $Date$
- */
-public class OctetString2Key {
-    /**
-     * Performs the function K-truncate to generate the AS reply key k.
-     *
-     * @param k
-     * @param x
-     * @return The AS reply key value.
-     */
-    public static byte[] kTruncate(int k, byte[] x) {
-        int numberOfBytes = k / 8;
-        byte[] result = new byte[numberOfBytes];
-
-        int count = 0;
-        byte[] filler = calculateIntegrity((byte) count, x);
-
-        int position = 0;
-
-        for (int i = 0; i < numberOfBytes; i++) {
-            if (position < filler.length) {
-                result[i] = filler[position];
-                position++;
-            } else {
-                count++;
-                filler = calculateIntegrity((byte) count, x);
-                position = 0;
-                result[i] = filler[position];
-                position++;
-            }
-        }
-
-        return result;
-    }
-
-
-    private static byte[] calculateIntegrity(byte count, byte[] data) {
-        try {
-            MessageDigest digester = MessageDigest.getInstance("SHA1");
-            digester.update(count);
-
-            return digester.digest(data);
-        } catch (NoSuchAlgorithmException nsae) {
-            return new byte[0];
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitPreauth.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitPreauth.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitPreauth.java
index 54f0693..8d99bbe 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitPreauth.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/pkinit/PkinitPreauth.java
@@ -24,10 +24,13 @@ import org.apache.kerby.kerberos.kerb.KrbErrorCode;
 import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.common.CheckSumUtil;
 import org.apache.kerby.kerberos.kerb.common.KrbUtil;
+import org.apache.kerby.kerberos.kerb.crypto.CheckSumHandler;
+import org.apache.kerby.kerberos.kerb.crypto.dh.DhServer;
 import org.apache.kerby.kerberos.kerb.preauth.PluginRequestContext;
 import org.apache.kerby.kerberos.kerb.preauth.pkinit.CMSMessageType;
 import org.apache.kerby.kerberos.kerb.preauth.pkinit.CertificateHelper;
 import org.apache.kerby.kerberos.kerb.preauth.pkinit.PkinitCrypto;
+import org.apache.kerby.kerberos.kerb.preauth.pkinit.PkinitPlgCryptoContext;
 import org.apache.kerby.kerberos.kerb.preauth.pkinit.PkinitPreauthMeta;
 import org.apache.kerby.kerberos.kerb.server.KdcContext;
 import org.apache.kerby.kerberos.kerb.server.preauth.AbstractPreauthPlugin;
@@ -35,6 +38,7 @@ import org.apache.kerby.kerberos.kerb.server.request.KdcRequest;
 import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
 import org.apache.kerby.kerberos.kerb.spec.base.CheckSum;
 import org.apache.kerby.kerberos.kerb.spec.base.CheckSumType;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionKey;
 import org.apache.kerby.kerberos.kerb.spec.base.PrincipalName;
 import org.apache.kerby.kerberos.kerb.spec.cms.DHParameter;
 import org.apache.kerby.kerberos.kerb.spec.cms.SubjectPublicKeyInfo;
@@ -51,13 +55,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import sun.security.pkcs.ContentInfo;
 import sun.security.pkcs.PKCS7;
-import sun.security.pkcs.SignerInfo;
-import sun.security.util.DerValue;
-import sun.security.util.ObjectIdentifier;
-import sun.security.x509.AlgorithmId;
 
 import javax.crypto.interfaces.DHPublicKey;
-import javax.crypto.spec.DHPublicKeySpec;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
@@ -65,10 +64,7 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigInteger;
-import java.security.KeyFactory;
-import java.security.NoSuchAlgorithmException;
 import java.security.cert.X509Certificate;
-import java.security.spec.InvalidKeySpecException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -80,7 +76,6 @@ public class PkinitPreauth extends AbstractPreauthPlugin {
 
     private static final Logger LOG = LoggerFactory.getLogger(PkinitPreauth.class);
     private final Map<String, PkinitKdcContext> pkinitContexts;
-    private static final String ID_PKINIT_DHKEYDATA = "1.3.6.1.5.2.3.2";
 
     public PkinitPreauth() {
         super(new PkinitPreauthMeta());
@@ -133,7 +128,7 @@ public class PkinitPreauth extends AbstractPreauthPlugin {
             byte[] signedAuthPack = paPkAsReq.getSignedAuthPack();
             PKCS7 pkcs7 = null;
             try {
-                pkcs7 = PkinitCrypto.verifyCMSSignedData(pkinitContext.cryptoctx,
+                pkcs7 = PkinitCrypto.verifyCMSSignedData(
                         CMSMessageType.CMS_SIGN_CLIENT, signedAuthPack);
             } catch (IOException e) {
                 e.getMessage();
@@ -180,16 +175,18 @@ public class PkinitPreauth extends AbstractPreauthPlugin {
 
             CheckSum expectedCheckSum = null;
             try {
+//                expectedCheckSum = CheckSumUtil.makeCheckSum(CheckSumType.NIST_SHA,
+//                        kdcRequest.getKdcReq().getReqBody().encode());
                 expectedCheckSum = CheckSumUtil.makeCheckSum(CheckSumType.NIST_SHA,
-                        kdcRequest.getKdcReq().getReqBody().encode());
+                        kdcRequest.getReqBodyBytes());
             } catch (KrbException e) {
                 LOG.error("Unable to calculate AS REQ checksum.", e.getMessage());
             }
 
+
             CheckSum receivedCheckSum = KrbCodec.decode(pkAuthenticator.getPaChecksum(), CheckSum.class);
 
-            if (expectedCheckSum.encodingLength() != receivedCheckSum.encodingLength()
-                    || !Arrays.equals(expectedCheckSum.getChecksum(), receivedCheckSum.getChecksum())) {
+            if(!CheckSumHandler.verify(receivedCheckSum, kdcRequest.getReqBodyBytes())) {
                 LOG.debug("Received checksum type: " + receivedCheckSum.getCksumtype()
                         + ", received checksum length: " + receivedCheckSum.encodingLength()
                         + ", expected checksum type: " + expectedCheckSum.getCksumtype()
@@ -199,28 +196,15 @@ public class PkinitPreauth extends AbstractPreauthPlugin {
                 throw new KrbException(KrbErrorCode.KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED, errorMessage);
             }
 
-            BigInteger p = dhParameter.getP();
-            BigInteger g = dhParameter.getG();
-
             SubjectPublicKeyInfo publicKeyInfo = authPack.getClientPublicValue();
             byte[] clientSubjectPubKey = publicKeyInfo.getSubjectPubKey().getValue();
             Asn1Integer clientPubKey = KrbCodec.decode(clientSubjectPubKey, Asn1Integer.class);
             BigInteger y = clientPubKey.getValue();
 
-            DHPublicKeySpec dhPublicKeySpec = new DHPublicKeySpec(y, p, g);
+            BigInteger p = dhParameter.getP();
+            BigInteger g = dhParameter.getG();
 
-            KeyFactory keyFactory = null;
-            try {
-                keyFactory = KeyFactory.getInstance("DH");
-            } catch (NoSuchAlgorithmException e) {
-                e.printStackTrace();
-            }
-            DHPublicKey dhPublicKey = null;
-            try {
-                dhPublicKey = (DHPublicKey) keyFactory.generatePublic(dhPublicKeySpec);
-            } catch (InvalidKeySpecException e) {
-                e.printStackTrace();
-            }
+            DHPublicKey dhPublicKey = PkinitCrypto.createDHPublicKey(p, g, y);
 
             DhServer server = new DhServer();
             DHPublicKey serverPubKey = null;
@@ -229,11 +213,14 @@ public class PkinitPreauth extends AbstractPreauthPlugin {
             } catch (Exception e) {
                 e.printStackTrace();
             }
-            server.generateKey(null, null);
+            EncryptionKey secretKey = server.generateKey(null, null, kdcRequest.getEncryptionType());
+
+            // Set the DH shared key as the client key
+            kdcRequest.setClientKey(secretKey);
 
             String identity = pkinitContext.identityOpts.identity;
 
-            PaPkAsRep paPkAsRep = makePaPkAsRep(serverPubKey, identity);
+            PaPkAsRep paPkAsRep = makePaPkAsRep(pkinitContext.cryptoctx, serverPubKey, identity);
             PaDataEntry paDataEntry = makeEntry(paPkAsRep);
 
             kdcRequest.getPreauthContext().getOutputPaData().add(paDataEntry);
@@ -260,11 +247,13 @@ public class PkinitPreauth extends AbstractPreauthPlugin {
 
         PaDataEntry paDataEntry = new PaDataEntry();
         paDataEntry.setPaDataType(PaDataType.PK_AS_REP);
-        paDataEntry.setPaDataValue(paPkAsRep.encode());
+        //TODO CHOICE
+        paDataEntry.setPaDataValue(paPkAsRep.getDHRepInfo().encode());
         return paDataEntry;
     }
 
-    private PaPkAsRep makePaPkAsRep(DHPublicKey severPubKey, String identityString) {
+    private PaPkAsRep makePaPkAsRep(PkinitPlgCryptoContext cryptoContext,
+                                    DHPublicKey severPubKey, String identityString) {
 
         List<String> identityList = Arrays.asList(identityString.split(","));
 
@@ -297,9 +286,7 @@ public class PkinitPreauth extends AbstractPreauthPlugin {
         }
 
         PaPkAsRep paPkAsRep = new PaPkAsRep();
-
         DHRepInfo dhRepInfo = new DHRepInfo();
-
         KdcDHKeyInfo kdcDhKeyInfo = new KdcDHKeyInfo();
 
         Asn1Integer publickey = new Asn1Integer(severPubKey.getY());
@@ -308,9 +295,12 @@ public class PkinitPreauth extends AbstractPreauthPlugin {
         kdcDhKeyInfo.setDHKeyExpiration(
                 new KerberosTime(System.currentTimeMillis() + KerberosTime.DAY));
 
+
         ByteArrayOutputStream signedData = null;
         try {
-            signedData = cmsSignedDataCreate(kdcDhKeyInfo, certificates);
+            signedData = PkinitCrypto.cmsSignedDataCreate(kdcDhKeyInfo.encode(),
+                    cryptoContext.getIdPkinitDHKeyDataOID(),
+                    certificates.toArray(new X509Certificate[certificates.size()]));
         } catch (IOException e) {
             e.printStackTrace();
         }
@@ -323,28 +313,6 @@ public class PkinitPreauth extends AbstractPreauthPlugin {
         return paPkAsRep;
     }
 
-
-    public static ContentInfo createContentInfo(byte[] data, ObjectIdentifier oid) {
-
-        ContentInfo contentInfo = new ContentInfo(
-                oid,
-                new DerValue(DerValue.tag_OctetString, data));
-        return contentInfo;
-    }
-
-    public static ByteArrayOutputStream cmsSignedDataCreate(KdcDHKeyInfo kdcDHKeyInfo,
-                                                            List<X509Certificate> certificates) throws IOException {
-
-        ObjectIdentifier oid = new ObjectIdentifier(ID_PKINIT_DHKEYDATA);
-        ContentInfo contentInfo = createContentInfo(kdcDHKeyInfo.encode(), oid);
-
-        PKCS7 p7 = new PKCS7(new AlgorithmId[0], contentInfo,
-                certificates.toArray(new X509Certificate[certificates.size()]), new SignerInfo[0]);
-        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-        p7.encodeSignedData(bytes);
-        return bytes;
-    }
-
     public boolean checkClockskew(KdcRequest kdcRequest, KerberosTime time) throws KrbException {
         long clockSkew = kdcRequest.getKdcContext().getConfig().getAllowableClockSkew() * 1000;
 

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
index 6ccd774..69f43af 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
@@ -32,6 +32,7 @@ import org.apache.kerby.kerberos.kerb.spec.base.KeyUsage;
 import org.apache.kerby.kerberos.kerb.spec.base.LastReq;
 import org.apache.kerby.kerberos.kerb.spec.base.LastReqEntry;
 import org.apache.kerby.kerberos.kerb.spec.base.LastReqType;
+import org.apache.kerby.kerberos.kerb.spec.base.NameType;
 import org.apache.kerby.kerberos.kerb.spec.base.PrincipalName;
 import org.apache.kerby.kerberos.kerb.spec.kdc.AsRep;
 import org.apache.kerby.kerberos.kerb.spec.kdc.AsReq;
@@ -80,6 +81,9 @@ public class AsRequest extends KdcRequest {
         } else {
             clientEntry = getEntry(clientPrincipal.getName());
         }
+        if(isAnonymous()) {
+            clientEntry.setPrincipal(new PrincipalName(clientPrincipal.getName(), NameType.NT_WELLKNOWN));
+        }
 
         if (clientEntry == null) {
             LOG.warn("Can't get the client entry.");

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
index 2a014b1..ef5ee33 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
@@ -93,9 +93,11 @@ public abstract class KdcRequest {
     private PrincipalName serverPrincipal;
     private byte[] innerBodyout;
     private AuthToken token;
-    private Boolean isToken = false;
-    private Boolean isPkinit = false;
+    private boolean isToken = false;
+    private boolean isPkinit = false;
+    private boolean isAnonymous = false;
     private EncryptionKey sessionKey;
+    private byte[] bodybytes;
 
     /**
      * Get session key.
@@ -164,6 +166,7 @@ public abstract class KdcRequest {
         checkVersion();
         checkTgsEntry();
         kdcFindFast();
+        authenticate();
         if (PreauthHandler.isToken(getKdcReq().getPaData())) {
             isToken = true;
             preauth();
@@ -177,7 +180,6 @@ public abstract class KdcRequest {
             checkServer();
             preauth();
         }
-        authenticate();
         issueTicket();
         makeReply();
     }
@@ -543,7 +545,7 @@ public abstract class KdcRequest {
         PaData preAuthData = request.getPaData();
 
         if (isPreauthRequired()) {
-            if (getKdcOptions().isFlagSet(KdcOption.REQUEST_ANONYMOUS) && !isPkinit) {
+            if (isAnonymous && !isPkinit) {
                 LOG.info("Need PKINIT.");
                 KrbError krbError = makePreAuthenticationError(kdcContext, request,
                         KrbErrorCode.KDC_ERR_PREAUTH_REQUIRED, true);
@@ -805,7 +807,19 @@ public abstract class KdcRequest {
         return isPkinit;
     }
 
+    protected boolean isAnonymous() {
+        return getKdcOptions().isFlagSet(KdcOption.REQUEST_ANONYMOUS);
+    }
+
     public KdcOptions getKdcOptions() {
         return kdcReq.getReqBody().getKdcOptions();
     }
+
+    public void setReqBodyBytes(byte[] bodyBytes) {
+        this.bodybytes = bodyBytes;
+    }
+
+    public byte[] getReqBodyBytes() {
+        return this.bodybytes;
+    }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/b9485672/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TicketIssuer.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TicketIssuer.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TicketIssuer.java
index 7021c27..88db09d 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TicketIssuer.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TicketIssuer.java
@@ -31,6 +31,7 @@ import org.apache.kerby.kerberos.kerb.spec.base.EncryptionKey;
 import org.apache.kerby.kerberos.kerb.spec.base.EncryptionType;
 import org.apache.kerby.kerberos.kerb.spec.base.HostAddresses;
 import org.apache.kerby.kerberos.kerb.spec.base.KeyUsage;
+import org.apache.kerby.kerberos.kerb.spec.base.NameType;
 import org.apache.kerby.kerberos.kerb.spec.base.PrincipalName;
 import org.apache.kerby.kerberos.kerb.spec.base.TransitedEncoding;
 import org.apache.kerby.kerberos.kerb.spec.base.TransitedEncodingType;
@@ -218,7 +219,11 @@ public abstract class TicketIssuer {
         if (kdcRequest.isToken()) {
             return new PrincipalName(kdcRequest.getToken().getSubject());
         } else {
-            return getKdcReq().getReqBody().getCname();
+            PrincipalName principalName = getKdcReq().getReqBody().getCname();
+            if(getKdcRequest().isAnonymous()) {
+                principalName.setNameType(NameType.NT_WELLKNOWN);
+            }
+            return principalName;
         }
     }
 


Mime
View raw message