jdk/src/share/classes/sun/security/krb5/internal/crypto/dk/Des3DkCrypto.java
changeset 2 90ce3da70b43
child 2917 fcd464c4e52c
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2004-2007 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.security.krb5.internal.crypto.dk;
       
    27 
       
    28 import javax.crypto.Cipher;
       
    29 import javax.crypto.Mac;
       
    30 import javax.crypto.SecretKeyFactory;
       
    31 import javax.crypto.SecretKey;
       
    32 import javax.crypto.spec.SecretKeySpec;
       
    33 import javax.crypto.spec.DESKeySpec;
       
    34 import javax.crypto.spec.DESedeKeySpec;
       
    35 import javax.crypto.spec.IvParameterSpec;
       
    36 import java.security.spec.KeySpec;
       
    37 import java.security.GeneralSecurityException;
       
    38 import java.security.InvalidKeyException;
       
    39 import java.util.Arrays;
       
    40 
       
    41 public class Des3DkCrypto extends DkCrypto {
       
    42 
       
    43     private static final byte[] ZERO_IV = new byte[] {0, 0, 0, 0, 0, 0, 0, 0};
       
    44 
       
    45     public Des3DkCrypto() {
       
    46     }
       
    47 
       
    48     protected int getKeySeedLength() {
       
    49         return 168;   // bits; 3DES key material has 21 bytes
       
    50     }
       
    51 
       
    52     public byte[] stringToKey(char[] salt) throws GeneralSecurityException {
       
    53         byte[] saltUtf8 = null;
       
    54         try {
       
    55             saltUtf8 = charToUtf8(salt);
       
    56             return stringToKey(saltUtf8, null);
       
    57         } finally {
       
    58             if (saltUtf8 != null) {
       
    59                 Arrays.fill(saltUtf8, (byte)0);
       
    60             }
       
    61             // Caller responsible for clearing its own salt
       
    62         }
       
    63     }
       
    64 
       
    65     private byte[] stringToKey(byte[] secretAndSalt, byte[] opaque)
       
    66         throws GeneralSecurityException {
       
    67 
       
    68         if (opaque != null && opaque.length > 0) {
       
    69             throw new RuntimeException("Invalid parameter to stringToKey");
       
    70         }
       
    71 
       
    72         byte[] tmpKey = randomToKey(nfold(secretAndSalt, getKeySeedLength()));
       
    73         return dk(tmpKey, KERBEROS_CONSTANT);
       
    74     }
       
    75 
       
    76     public byte[] parityFix(byte[] value)
       
    77         throws GeneralSecurityException {
       
    78         // fix key parity
       
    79         setParityBit(value);
       
    80         return value;
       
    81     }
       
    82 
       
    83     /*
       
    84      * From RFC 3961.
       
    85      *
       
    86      * The 168 bits of random key data are converted to a protocol key value
       
    87      * as follows.  First, the 168 bits are divided into three groups of 56
       
    88      * bits, which are expanded individually into 64 bits as in des3Expand().
       
    89      * Result is a 24 byte (192-bit) key.
       
    90      */
       
    91     protected byte[] randomToKey(byte[] in) {
       
    92         if (in.length != 21) {
       
    93             throw new IllegalArgumentException("input must be 168 bits");
       
    94         }
       
    95 
       
    96         byte[] one = keyCorrection(des3Expand(in, 0, 7));
       
    97         byte[] two = keyCorrection(des3Expand(in, 7, 14));
       
    98         byte[] three = keyCorrection(des3Expand(in, 14, 21));
       
    99 
       
   100         byte[] key = new byte[24];
       
   101         System.arraycopy(one, 0, key, 0, 8);
       
   102         System.arraycopy(two, 0, key, 8, 8);
       
   103         System.arraycopy(three, 0, key, 16, 8);
       
   104 
       
   105         return key;
       
   106     }
       
   107 
       
   108     private static byte[] keyCorrection(byte[] key) {
       
   109         // check for weak key
       
   110         try {
       
   111             if (DESKeySpec.isWeak(key, 0)) {
       
   112                 key[7] = (byte)(key[7] ^ 0xF0);
       
   113             }
       
   114         } catch (InvalidKeyException ex) {
       
   115             // swallow, since it should never happen
       
   116         }
       
   117         return key;
       
   118     }
       
   119 
       
   120     /**
       
   121      * From RFC 3961.
       
   122      *
       
   123      * Expands a 7-byte array into an 8-byte array that contains parity bits.
       
   124      * The 56 bits are expanded into 64 bits as follows:
       
   125      *   1  2  3  4  5  6  7  p
       
   126      *   9 10 11 12 13 14 15  p
       
   127      *   17 18 19 20 21 22 23  p
       
   128      *   25 26 27 28 29 30 31  p
       
   129      *   33 34 35 36 37 38 39  p
       
   130      *   41 42 43 44 45 46 47  p
       
   131      *   49 50 51 52 53 54 55  p
       
   132      *   56 48 40 32 24 16  8  p
       
   133      *
       
   134      * (PI,P2,...,P8) are reserved for parity bits computed on the preceding
       
   135      * seven independent bits and set so that the parity of the octet is odd,
       
   136      * i.e., there is an odd number of "1" bits in the octet.
       
   137      *
       
   138      * @param start index of starting byte (inclusive)
       
   139      * @param end index of ending byte (exclusive)
       
   140      */
       
   141     private static byte[] des3Expand(byte[] input, int start, int end) {
       
   142         if ((end - start) != 7)
       
   143             throw new IllegalArgumentException(
       
   144                 "Invalid length of DES Key Value:" + start + "," + end);
       
   145 
       
   146         byte[] result = new byte[8];
       
   147         byte last = 0;
       
   148         System.arraycopy(input, start, result, 0, 7);
       
   149         byte posn = 0;
       
   150 
       
   151         // Fill in last row
       
   152         for (int i = start; i < end; i++) {
       
   153             byte bit = (byte) (input[i]&0x01);
       
   154             if (debug) {
       
   155                 System.out.println(i + ": " + Integer.toHexString(input[i]) +
       
   156                     " bit= " + Integer.toHexString(bit));
       
   157             }
       
   158             ++posn;
       
   159             if (bit != 0) {
       
   160                 last |= (bit<<posn);
       
   161             }
       
   162         }
       
   163 
       
   164         if (debug) {
       
   165             System.out.println("last: " + Integer.toHexString(last));
       
   166         }
       
   167         result[7] = last;
       
   168         setParityBit(result);
       
   169         return result;
       
   170     }
       
   171 
       
   172     /* Mask used to check for parity adjustment */
       
   173     private static final byte[] PARITY_BIT_MASK = {
       
   174         (byte)0x80, (byte)0x40, (byte)0x20, (byte)0x10,
       
   175         (byte)0x08, (byte)0x04, (byte)0x02
       
   176     };
       
   177 
       
   178     /**
       
   179      * Sets the parity bit (0th bit) in each byte so that each byte
       
   180      * contains an odd number of 1's.
       
   181      */
       
   182     private static void setParityBit(byte[] key) {
       
   183         for (int i = 0; i < key.length; i++) {
       
   184             int bitCount = 0;
       
   185             for (int maskIndex = 0;
       
   186                  maskIndex < PARITY_BIT_MASK.length; maskIndex++) {
       
   187                 if ((key[i] & PARITY_BIT_MASK[maskIndex])
       
   188                     == PARITY_BIT_MASK[maskIndex]) {
       
   189                     bitCount++;
       
   190                 }
       
   191             }
       
   192             if ((bitCount & 0x01) == 1) {
       
   193                 // Odd number of 1 bits in the top 7 bits. Set parity bit to 0
       
   194                 key[i] = (byte)(key[i] & (byte)0xfe);
       
   195             } else {
       
   196                 // Even number of 1 bits in the top 7 bits. Set parity bit to 1
       
   197                 key[i] = (byte)(key[i] | 1);
       
   198             }
       
   199         }
       
   200     }
       
   201 
       
   202     protected Cipher getCipher(byte[] key, byte[] ivec, int mode)
       
   203         throws GeneralSecurityException {
       
   204         // NoSuchAlgorithException
       
   205         SecretKeyFactory factory = SecretKeyFactory.getInstance("desede");
       
   206 
       
   207         // InvalidKeyException
       
   208         KeySpec spec = new DESedeKeySpec(key, 0);
       
   209 
       
   210         // InvalidKeySpecException
       
   211         SecretKey secretKey = factory.generateSecret(spec);
       
   212 
       
   213         // IV
       
   214         if (ivec == null) {
       
   215             ivec = ZERO_IV;
       
   216         }
       
   217 
       
   218         // NoSuchAlgorithmException, NoSuchPaddingException
       
   219         // NoSuchProviderException
       
   220         Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
       
   221         IvParameterSpec encIv = new IvParameterSpec(ivec, 0, ivec.length);
       
   222 
       
   223         // InvalidKeyException, InvalidAlgorithParameterException
       
   224         cipher.init(mode, secretKey, encIv);
       
   225 
       
   226         return cipher;
       
   227     }
       
   228 
       
   229     public int getChecksumLength() {
       
   230         return 20;  // bytes
       
   231     }
       
   232 
       
   233     protected byte[] getHmac(byte[] key, byte[] msg)
       
   234         throws GeneralSecurityException {
       
   235 
       
   236         SecretKey keyKi = new SecretKeySpec(key, "HmacSHA1");
       
   237         Mac m = Mac.getInstance("HmacSHA1");
       
   238         m.init(keyKi);
       
   239         return m.doFinal(msg);
       
   240     }
       
   241 }