123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- /*
- * 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 javax.security.auth.kerberos;
- import java.io.IOException;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
- import java.io.Serializable;
- import java.util.Arrays;
- import javax.crypto.Cipher;
- import javax.crypto.SecretKey;
- import javax.crypto.spec.IvParameterSpec;
- import javax.crypto.spec.SecretKeySpec;
- import javax.security.auth.DestroyFailedException;
- import javax.security.auth.Destroyable;
- import org.apache.harmony.auth.internal.kerberos.v5.EncryptionKey;
- import org.apache.harmony.auth.internal.nls.Messages;
- import org.apache.harmony.security.utils.Array;
- /**
- * This class encapsulates a Kerberos encryption key.
- *
- */
- class KeyImpl implements SecretKey, Destroyable, Serializable {
- private static final long serialVersionUID = -7889313790214321193L;
-
- private transient byte[] keyBytes;
- private transient int keyType;
-
- // indicates the ticket state
- private transient boolean destroyed;
- // Pre-calculated parity values
- // TODO the alternative for boolean table - any acceptable algorithm?
- private final static boolean[] PARITY = new boolean[] { false, true, true,
- false, true, false, false, true, true, false, false, true, false,
- true, true, false, true, false, false, true, false, true, true,
- false, false, true, true, false, true, false, false, true, true,
- false, false, true, false, true, true, false, false, true, true,
- false, true, false, false, true, false, true, true, false, true,
- false, false, true, true, false, false, true, false, true, true,
- false, true, false, false, true, false, true, true, false, false,
- true, true, false, true, false, false, true, false, true, true,
- false, true, false, false, true, true, false, false, true, false,
- true, true, false, false, true, true, false, true, false, false,
- true, true, false, false, true, false, true, true, false, true,
- false, false, true, false, true, true, false, false, true, true,
- false, true, false, false, true, true, false, false, true, false,
- true, true, false, false, true, true, false, true, false, false,
- true, false, true, true, false, true, false, false, true, true,
- false, false, true, false, true, true, false, false, true, true,
- false, true, false, false, true, true, false, false, true, false,
- true, true, false, true, false, false, true, false, true, true,
- false, false, true, true, false, true, false, false, true, false,
- true, true, false, true, false, false, true, true, false, false,
- true, false, true, true, false, true, false, false, true, false,
- true, true, false, false, true, true, false, true, false, false,
- true, true, false, false, true, false, true, true, false, false,
- true, true, false, true, false, false, true, false, true, true,
- false, true, false, false, true, true, false, false, true, false,
- true, true, false };
- // Pre-calculated reversed values
- // TODO any acceptable alternative algorithm instead of table?
- private static final byte[] REVERSE = new byte[] { 0, 64, 32, 96, 16, 80,
- 48, 112, 8, 72, 40, 104, 24, 88, 56, 120, 4, 68, 36, 100, 20, 84,
- 52, 116, 12, 76, 44, 108, 28, 92, 60, 124, 2, 66, 34, 98, 18, 82,
- 50, 114, 10, 74, 42, 106, 26, 90, 58, 122, 6, 70, 38, 102, 22, 86,
- 54, 118, 14, 78, 46, 110, 30, 94, 62, 126, 1, 65, 33, 97, 17, 81,
- 49, 113, 9, 73, 41, 105, 25, 89, 57, 121, 5, 69, 37, 101, 21, 85,
- 53, 117, 13, 77, 45, 109, 29, 93, 61, 125, 3, 67, 35, 99, 19, 83,
- 51, 115, 11, 75, 43, 107, 27, 91, 59, 123, 7, 71, 39, 103, 23, 87,
- 55, 119, 15, 79, 47, 111, 31, 95, 63, 127 };
- /**
- * creates a secret key from a given raw bytes
- *
- * @param keyBytes
- * @param keyType
- */
- public KeyImpl(byte[] keyBytes, int keyType) {
- this.keyBytes = new byte[keyBytes.length];
- System.arraycopy(keyBytes , 0, this.keyBytes, 0, this.keyBytes.length);
- this.keyType = keyType;
- }
- /**
- * creates a secret key from a given password
- *
- * @param principal
- * @param password
- * @param algorithm
- */
- public KeyImpl(KerberosPrincipal principal, char[] password, String algorithm) {
- //
- // See http://www.ietf.org/rfc/rfc3961.txt for algorithm description
- //
-
- if (principal == null || password == null) {
- throw new NullPointerException();
- }
- if (algorithm != null && "DES".compareTo(algorithm) != 0) { //$NON-NLS-1$
- throw new IllegalArgumentException(Messages.getString("auth.49")); //$NON-NLS-1$
- }
- keyType = 3; // DES algorithm
- keyBytes = new byte[8];
-
- String realm = principal.getRealm();
- String pname = principal.getName();
- StringBuilder buf = new StringBuilder();
- buf.append(password);
- buf.append(realm);
- buf.append(pname.substring(0, pname.length() - realm.length() - 1));
- byte[] tmp = org.apache.harmony.luni.util.Util.getUTF8Bytes(buf
- .toString());
- // pad with 0x00 to 8 byte boundary
- byte[] raw = new byte[tmp.length
- + ((tmp.length % 8) == 0 ? 0 : (8 - tmp.length % 8))];
- System.arraycopy(tmp, 0, raw, 0, tmp.length);
- long k1, k2 = 0;
- boolean isOdd = false;
- // for each 8-byte block in raw byte array
- for (int i = 0; i < raw.length; i = i + 8, isOdd = !isOdd) {
- k1 = 0;
- if (isOdd) {
- //reverse
- for (int j = 7; j > -1; j--) {
- k1 = (k1 << 7) + REVERSE[raw[i + j] & 0x7F];
- }
- } else {
- for (int j = 0; j < 8; j++) {
- k1 = (k1 << 7) + (raw[i + j] & 0x7F);
- }
- }
- k2 = k2 ^ k1;
- }
-
- // 56-bit long to byte array (8 bytes)
- for (int i = 7; i > -1; i--) {
- keyBytes[i] = (byte) k2;
- keyBytes[i] = (byte) (keyBytes[i] << 1);
- k2 = k2 >> 7;
- }
- keyCorrection(keyBytes);
- // calculate DES-CBC check sum
- try {
- Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding"); //$NON-NLS-1$
- // use tmp key as IV
- IvParameterSpec IV = new IvParameterSpec(keyBytes);
- // do DES encryption
- SecretKey secretKey = new SecretKeySpec(keyBytes, "DES"); //$NON-NLS-1$
- cipher.init(Cipher.ENCRYPT_MODE, secretKey, IV);
- byte[] enc = cipher.doFinal(raw);
- // final last block is check sum
- System.arraycopy(enc, enc.length - 8, keyBytes, 0, 8);
-
- keyCorrection(keyBytes);
- } catch (Exception e) {
- throw new RuntimeException(
- Messages.getString("auth.4A"), e); //$NON-NLS-1$
- }
- }
- private void keyCorrection(byte[] key) {
-
- // fix parity
- for (int i = 0; i < 8; i++) {
- if (!PARITY[key[i] & 0xFF]) {
- if ((key[i] & 0x01) == 0) {
- key[i]++;
- } else {
- key[i]--;
- }
- }
- }
-
- // TODO if is week do XOR
- //if(DESKeySpec.isWeak(keyBytes,0)){
- //}
- }
- /**
- * Method is described in
- * <code>getAlgorithm</code> in interface <code>Key</code>
- */
- public final String getAlgorithm() {
- checkState();
- if (keyType == 0) {
- return "NULL"; //$NON-NLS-1$
- }
- return "DES"; //$NON-NLS-1$
- }
-
- /**
- * Method is described in
- * <code>getFormat</code> in interface <code>Key</code>
- */
- public final String getFormat() {
- checkState();
- return "RAW"; //$NON-NLS-1$
- }
-
- /**
- * Method is described in
- * <code>getEncoded</code> in interface <code>Key</code>
- */
- public final byte[] getEncoded() {
- checkState();
- byte[] tmp = new byte[keyBytes.length];
- System.arraycopy(keyBytes, 0, tmp, 0, tmp.length);
- return tmp;
- }
- /**
- * Returns the key type for this key
- */
- public final int getKeyType() {
- checkState();
- return keyType;
- }
- /**
- * Destroys this key
- */
- public void destroy() throws DestroyFailedException {
- if (!destroyed) {
- Arrays.fill(keyBytes, (byte) 0);
- destroyed = true;
- }
-
- }
- /**
- * Determines if this key has been destroyed
- */
- public boolean isDestroyed() {
- return destroyed;
- }
- /**
- * A string representation of this key
- */
- @Override
- public String toString() {
- String s_key = null;
- StringBuilder sb = new StringBuilder();
-
- if (keyBytes.length == 0) {
- s_key = "Empty Key"; //$NON-NLS-1$
- } else {
- s_key = Array.toString(keyBytes," "); //$NON-NLS-1$
- }
- sb.append("EncryptionKey: ").append("KeyType = ").append(keyType); //$NON-NLS-1$ //$NON-NLS-2$
- sb.append("KeyBytes (Hex dump) = ").append(s_key); //$NON-NLS-1$
- return sb.toString();
- }
-
- /**
- * if a key is destroyed then IllegalStateException should be thrown
- */
- private void checkState() {
- if (destroyed) {
- throw new IllegalStateException (Messages.getString("auth.48")); //$NON-NLS-1$
- }
- }
- private void readObject(ObjectInputStream s) throws IOException,
- ClassNotFoundException {
- s.defaultReadObject();
- EncryptionKey ekey = (EncryptionKey) EncryptionKey.ASN1
- .decode((byte[]) s.readObject());
- keyType = ekey.getType();
- keyBytes = ekey.getValue();
- }
- private void writeObject(ObjectOutputStream s) throws IOException {
- if (destroyed) {
- throw new IOException(Messages.getString("auth.48")); //$NON-NLS-1$
- }
- s.defaultWriteObject();
- byte[] enc = EncryptionKey.ASN1.encode(new EncryptionKey(keyType,
- keyBytes));
- s.writeObject(enc);
- }
- }
|