1/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.  Oracle designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Oracle in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25/*
26 *  (C) Copyright IBM Corp. 1999 All Rights Reserved.
27 *  Copyright 1997 The Open Group Research Institute.  All rights reserved.
28 */
29
30package sun.security.krb5.internal.crypto;
31
32import sun.security.krb5.Checksum;
33import sun.security.krb5.Confounder;
34import sun.security.krb5.KrbCryptoException;
35import sun.security.krb5.internal.*;
36import javax.crypto.Cipher;
37import javax.crypto.SecretKey;
38import javax.crypto.spec.DESKeySpec;
39import java.security.MessageDigest;
40import java.security.Provider;
41import java.security.Security;
42import java.security.InvalidKeyException;
43
44public final class RsaMd5DesCksumType extends CksumType {
45
46    public RsaMd5DesCksumType() {
47    }
48
49    public int confounderSize() {
50        return 8;
51    }
52
53    public int cksumType() {
54        return Checksum.CKSUMTYPE_RSA_MD5_DES;
55    }
56
57    public boolean isSafe() {
58        return true;
59    }
60
61    public int cksumSize() {
62        return 24;
63    }
64
65    public int keyType() {
66        return Krb5.KEYTYPE_DES;
67    }
68
69    public int keySize() {
70        return 8;
71    }
72
73    /**
74     * Calculates keyed checksum.
75     * @param data the data used to generate the checksum.
76     * @param size length of the data.
77     * @param key the key used to encrypt the checksum.
78     * @return keyed checksum.
79     *
80     * @modified by Yanni Zhang, 12/08/99.
81     */
82    public byte[] calculateKeyedChecksum(byte[] data, int size, byte[] key,
83        int usage) throws KrbCryptoException {
84        //prepend confounder
85        byte[] new_data = new byte[size + confounderSize()];
86        byte[] conf = Confounder.bytes(confounderSize());
87        System.arraycopy(conf, 0, new_data, 0, confounderSize());
88        System.arraycopy(data, 0, new_data, confounderSize(), size);
89
90        //calculate md5 cksum
91        byte[] mdc_cksum = calculateChecksum(new_data, new_data.length);
92        byte[] cksum = new byte[cksumSize()];
93        System.arraycopy(conf, 0, cksum, 0, confounderSize());
94        System.arraycopy(mdc_cksum, 0, cksum, confounderSize(),
95                         cksumSize() - confounderSize());
96
97        //compute modified key
98        byte[] new_key = new byte[keySize()];
99        System.arraycopy(key, 0, new_key, 0, key.length);
100        for (int i = 0; i < new_key.length; i++)
101        new_key[i] = (byte)(new_key[i] ^ 0xf0);
102        //check for weak keys
103        try {
104            if (DESKeySpec.isWeak(new_key, 0)) {
105                new_key[7] = (byte)(new_key[7] ^ 0xF0);
106            }
107        } catch (InvalidKeyException ex) {
108            // swallow, since it should never happen
109        }
110        byte[] ivec = new byte[new_key.length];
111
112        //des-cbc encrypt
113        byte[] enc_cksum = new byte[cksum.length];
114        Des.cbc_encrypt(cksum, enc_cksum, new_key, ivec, true);
115        return enc_cksum;
116    }
117
118    /**
119     * Verifies keyed checksum.
120     * @param data the data.
121     * @param size the length of data.
122     * @param key the key used to encrypt the checksum.
123     * @param checksum the checksum.
124     * @return true if verification is successful.
125     *
126     * @modified by Yanni Zhang, 12/08/99.
127     */
128    public boolean verifyKeyedChecksum(byte[] data, int size,
129        byte[] key, byte[] checksum, int usage) throws KrbCryptoException {
130        //decrypt checksum
131        byte[] cksum = decryptKeyedChecksum(checksum, key);
132
133        //prepend confounder
134        byte[] new_data = new byte[size + confounderSize()];
135        System.arraycopy(cksum, 0, new_data, 0, confounderSize());
136        System.arraycopy(data, 0, new_data, confounderSize(), size);
137
138        byte[] new_cksum = calculateChecksum(new_data, new_data.length);
139        //extract original cksum value
140        byte[] orig_cksum = new byte[cksumSize() - confounderSize()];
141        System.arraycopy(cksum,  confounderSize(), orig_cksum, 0,
142                         cksumSize() - confounderSize());
143
144        return isChecksumEqual(orig_cksum, new_cksum);
145    }
146
147    /**
148     * Decrypts keyed checksum.
149     * @param enc_cksum the buffer for encrypted checksum.
150     * @param key the key.
151     * @return the checksum.
152     *
153     * @modified by Yanni Zhang, 12/08/99.
154     */
155    private byte[] decryptKeyedChecksum(byte[] enc_cksum, byte[] key) throws KrbCryptoException {
156        //compute modified key
157        byte[] new_key = new byte[keySize()];
158        System.arraycopy(key, 0, new_key, 0, key.length);
159        for (int i = 0; i < new_key.length; i++)
160        new_key[i] = (byte)(new_key[i] ^ 0xf0);
161        //check for weak keys
162        try {
163            if (DESKeySpec.isWeak(new_key, 0)) {
164                new_key[7] = (byte)(new_key[7] ^ 0xF0);
165            }
166        } catch (InvalidKeyException ex) {
167            // swallow, since it should never happen
168        }
169        byte[] ivec = new byte[new_key.length];
170
171        byte[] cksum = new byte[enc_cksum.length];
172        Des.cbc_encrypt(enc_cksum, cksum, new_key, ivec, false);
173        return cksum;
174    }
175
176    /**
177     * Calculates checksum using MD5.
178     * @param data the data used to generate the checksum.
179     * @param size length of the data.
180     * @return the checksum.
181     *
182     * @modified by Yanni Zhang, 12/08/99.
183     */
184    public byte[] calculateChecksum(byte[] data, int size) throws KrbCryptoException{
185        MessageDigest md5;
186        byte[] result = null;
187        try {
188            md5 = MessageDigest.getInstance("MD5");
189        } catch (Exception e) {
190            throw new KrbCryptoException("JCE provider may not be installed. " + e.getMessage());
191        }
192        try {
193            md5.update(data);
194            result = md5.digest();
195        } catch (Exception e) {
196            throw new KrbCryptoException(e.getMessage());
197        }
198        return result;
199    }
200
201}
202