0N/A/*
2362N/A * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
0N/A */
0N/A
0N/A/*
0N/A * Copyright (C) 1998 by the FundsXpress, INC.
0N/A *
0N/A * All rights reserved.
0N/A *
0N/A * Export of this software from the United States of America may require
0N/A * a specific license from the United States Government. It is the
0N/A * responsibility of any person or organization contemplating export to
0N/A * obtain such a license before exporting.
0N/A *
0N/A * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
0N/A * distribute this software and its documentation for any purpose and
0N/A * without fee is hereby granted, provided that the above copyright
0N/A * notice appear in all copies and that both that copyright notice and
0N/A * this permission notice appear in supporting documentation, and that
0N/A * the name of FundsXpress. not be used in advertising or publicity pertaining
0N/A * to distribution of the software without specific, written prior
0N/A * permission. FundsXpress makes no representations about the suitability of
0N/A * this software for any purpose. It is provided "as is" without express
0N/A * or implied warranty.
0N/A *
0N/A * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
0N/A * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
0N/A * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
0N/A */
0N/A
0N/Apackage sun.security.krb5.internal.crypto.dk;
0N/A
0N/Aimport javax.crypto.Cipher;
0N/Aimport javax.crypto.Mac;
0N/Aimport java.security.GeneralSecurityException;
0N/Aimport java.io.UnsupportedEncodingException;
0N/Aimport java.util.Arrays;
0N/Aimport java.io.ByteArrayInputStream;
0N/Aimport java.io.ByteArrayOutputStream;
0N/Aimport java.nio.charset.Charset;
0N/Aimport java.nio.CharBuffer;
0N/Aimport java.nio.ByteBuffer;
0N/Aimport sun.misc.HexDumpEncoder;
0N/Aimport sun.security.krb5.Confounder;
0N/Aimport sun.security.krb5.internal.crypto.KeyUsage;
0N/Aimport sun.security.krb5.KrbCryptoException;
0N/A
0N/A/**
0N/A * Implements Derive Key cryptography functionality as defined in RFC 3961.
0N/A * http://www.ietf.org/rfc/rfc3961.txt
0N/A *
0N/A * This is an abstract class. Concrete subclasses need to implement
0N/A * the abstract methods.
0N/A */
0N/A
0N/Apublic abstract class DkCrypto {
0N/A
0N/A protected static final boolean debug = false;
0N/A
0N/A // These values correspond to the ASCII encoding for the string "kerberos"
0N/A static final byte[] KERBEROS_CONSTANT =
0N/A {0x6b, 0x65, 0x72, 0x62, 0x65, 0x72, 0x6f, 0x73};
0N/A
0N/A protected abstract int getKeySeedLength(); // in bits
0N/A
0N/A protected abstract byte[] randomToKey(byte[] in);
0N/A
0N/A protected abstract Cipher getCipher(byte[] key, byte[] ivec, int mode)
0N/A throws GeneralSecurityException;
0N/A
0N/A public abstract int getChecksumLength(); // in bytes
0N/A
0N/A protected abstract byte[] getHmac(byte[] key, byte[] plaintext)
0N/A throws GeneralSecurityException;
0N/A
0N/A /**
0N/A * From RFC 3961.
0N/A *
0N/A * encryption function conf = random string of length c
0N/A * pad = shortest string to bring confounder
0N/A * and plaintext to a length that's a
0N/A * multiple of m
0N/A * (C1, newIV) = E(Ke, conf | plaintext | pad,
0N/A * oldstate.ivec)
0N/A * H1 = HMAC(Ki, conf | plaintext | pad)
0N/A * ciphertext = C1 | H1[1..h]
0N/A * newstate.ivec = newIV
0N/A *
0N/A * @param ivec initial vector to use when initializing the cipher; if null,
0N/A * then blocksize number of zeros are used,
0N/A * @param new_ivec if non-null, it is updated upon return to be the
0N/A * new ivec to use when calling encrypt next time
0N/A */
0N/A public byte[] encrypt(byte[] baseKey, int usage,
0N/A byte[] ivec, byte[] new_ivec, byte[] plaintext, int start, int len)
0N/A throws GeneralSecurityException, KrbCryptoException {
0N/A
0N/A if (!KeyUsage.isValid(usage)) {
0N/A throw new GeneralSecurityException("Invalid key usage number: "
0N/A + usage);
0N/A }
0N/A
0N/A byte[] Ke = null;
0N/A byte[] Ki = null;
0N/A
0N/A try {
0N/A // Derive encryption key
0N/A
0N/A byte[] constant = new byte[5];
0N/A constant[0] = (byte) ((usage>>24)&0xff);
0N/A constant[1] = (byte) ((usage>>16)&0xff);
0N/A constant[2] = (byte) ((usage>>8)&0xff);
0N/A constant[3] = (byte) (usage&0xff);
0N/A
0N/A constant[4] = (byte) 0xaa;
0N/A
0N/A Ke = dk(baseKey, constant);
0N/A if (debug) {
0N/A System.err.println("usage: " + usage);
0N/A if (ivec != null) {
0N/A traceOutput("old_state.ivec", ivec, 0, ivec.length);
0N/A }
0N/A traceOutput("plaintext", plaintext, start, Math.min(len, 32));
0N/A traceOutput("constant", constant, 0, constant.length);
0N/A traceOutput("baseKey", baseKey, 0, baseKey.length);
0N/A traceOutput("Ke", Ke, 0, Ke.length);
0N/A }
0N/A
0N/A // Encrypt
0N/A // C1 = E(Ke, conf | plaintext | pad, oldivec)
0N/A Cipher encCipher = getCipher(Ke, ivec, Cipher.ENCRYPT_MODE);
0N/A int blockSize = encCipher.getBlockSize();
0N/A byte[] confounder = Confounder.bytes(blockSize);
0N/A
0N/A int plainSize = roundup(confounder.length + len, blockSize);
0N/A if (debug) {
0N/A System.err.println("confounder = " + confounder.length +
0N/A "; plaintext = " + len + "; padding = " +
0N/A (plainSize - confounder.length - len) + "; total = " +
0N/A plainSize);
0N/A traceOutput("confounder", confounder, 0, confounder.length);
0N/A }
0N/A
0N/A byte[] toBeEncrypted = new byte[plainSize];
0N/A System.arraycopy(confounder, 0, toBeEncrypted,
0N/A 0, confounder.length);
0N/A System.arraycopy(plaintext, start, toBeEncrypted,
0N/A confounder.length, len);
0N/A
0N/A // Set padding bytes to zero
0N/A Arrays.fill(toBeEncrypted, confounder.length + len, plainSize,
0N/A (byte)0);
0N/A
0N/A int cipherSize = encCipher.getOutputSize(plainSize);
0N/A int ccSize = cipherSize + getChecksumLength(); // cipher | hmac
0N/A
0N/A byte[] ciphertext = new byte[ccSize];
0N/A
0N/A encCipher.doFinal(toBeEncrypted, 0, plainSize, ciphertext, 0);
0N/A
0N/A // Update ivec for next operation
0N/A // (last blockSize bytes of ciphertext)
0N/A // newstate.ivec = newIV
0N/A if (new_ivec != null && new_ivec.length == blockSize) {
0N/A System.arraycopy(ciphertext, cipherSize - blockSize,
0N/A new_ivec, 0, blockSize);
0N/A if (debug) {
0N/A traceOutput("new_ivec", new_ivec, 0, new_ivec.length);
0N/A }
0N/A }
0N/A
0N/A // Derive integrity key
0N/A constant[4] = (byte) 0x55;
0N/A Ki = dk(baseKey, constant);
0N/A if (debug) {
0N/A traceOutput("constant", constant, 0, constant.length);
0N/A traceOutput("Ki", Ki, 0, Ke.length);
0N/A }
0N/A
0N/A // Generate checksum
0N/A // H1 = HMAC(Ki, conf | plaintext | pad)
0N/A byte[] hmac = getHmac(Ki, toBeEncrypted);
0N/A
0N/A if (debug) {
0N/A traceOutput("hmac", hmac, 0, hmac.length);
0N/A traceOutput("ciphertext", ciphertext, 0,
0N/A Math.min(ciphertext.length, 32));
0N/A }
0N/A
0N/A // C1 | H1[1..h]
0N/A System.arraycopy(hmac, 0, ciphertext, cipherSize,
0N/A getChecksumLength());
0N/A return ciphertext;
0N/A } finally {
0N/A if (Ke != null) {
0N/A Arrays.fill(Ke, 0, Ke.length, (byte) 0);
0N/A }
0N/A if (Ki != null) {
0N/A Arrays.fill(Ki, 0, Ki.length, (byte) 0);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Performs encryption using given key only; does not add
0N/A * confounder, padding, or checksum. Incoming data to be encrypted
0N/A * assumed to have the correct blocksize.
0N/A * Ignore key usage.
0N/A */
0N/A public byte[] encryptRaw(byte[] baseKey, int usage,
0N/A byte[] ivec, byte[] plaintext, int start, int len)
0N/A throws GeneralSecurityException, KrbCryptoException {
0N/A
0N/A if (debug) {
0N/A System.err.println("usage: " + usage);
0N/A if (ivec != null) {
0N/A traceOutput("old_state.ivec", ivec, 0, ivec.length);
0N/A }
0N/A traceOutput("plaintext", plaintext, start, Math.min(len, 32));
0N/A traceOutput("baseKey", baseKey, 0, baseKey.length);
0N/A }
0N/A
0N/A // Encrypt
0N/A Cipher encCipher = getCipher(baseKey, ivec, Cipher.ENCRYPT_MODE);
0N/A int blockSize = encCipher.getBlockSize();
0N/A
0N/A if ((len % blockSize) != 0) {
0N/A throw new GeneralSecurityException(
0N/A "length of data to be encrypted (" + len +
0N/A ") is not a multiple of the blocksize (" + blockSize + ")");
0N/A }
0N/A
0N/A int cipherSize = encCipher.getOutputSize(len);
0N/A byte[] ciphertext = new byte[cipherSize];
0N/A
0N/A encCipher.doFinal(plaintext, 0, len, ciphertext, 0);
0N/A return ciphertext;
0N/A }
0N/A
0N/A /**
0N/A * Decrypts data using specified key and initial vector.
0N/A * @param baseKey encryption key to use
0N/A * @param ciphertext encrypted data to be decrypted
0N/A * @param usage ignored
0N/A */
0N/A public byte[] decryptRaw(byte[] baseKey, int usage, byte[] ivec,
0N/A byte[] ciphertext, int start, int len)
0N/A throws GeneralSecurityException {
0N/A
0N/A if (debug) {
0N/A System.err.println("usage: " + usage);
0N/A if (ivec != null) {
0N/A traceOutput("old_state.ivec", ivec, 0, ivec.length);
0N/A }
0N/A traceOutput("ciphertext", ciphertext, start, Math.min(len, 32));
0N/A traceOutput("baseKey", baseKey, 0, baseKey.length);
0N/A }
0N/A
0N/A Cipher decCipher = getCipher(baseKey, ivec, Cipher.DECRYPT_MODE);
0N/A
0N/A int blockSize = decCipher.getBlockSize();
0N/A
0N/A if ((len % blockSize) != 0) {
0N/A throw new GeneralSecurityException(
0N/A "length of data to be decrypted (" + len +
0N/A ") is not a multiple of the blocksize (" + blockSize + ")");
0N/A }
0N/A
0N/A byte[] decrypted = decCipher.doFinal(ciphertext, start, len);
0N/A
0N/A if (debug) {
0N/A traceOutput("decrypted", decrypted, 0,
0N/A Math.min(decrypted.length, 32));
0N/A }
0N/A
0N/A return decrypted;
0N/A }
0N/A
0N/A /**
0N/A * @param baseKey key from which keys are to be derived using usage
0N/A * @param ciphertext E(Ke, conf | plaintext | padding, ivec) | H1[1..h]
0N/A */
0N/A public byte[] decrypt(byte[] baseKey, int usage, byte[] ivec,
0N/A byte[] ciphertext, int start, int len) throws GeneralSecurityException {
0N/A
0N/A if (!KeyUsage.isValid(usage)) {
0N/A throw new GeneralSecurityException("Invalid key usage number: "
0N/A + usage);
0N/A }
0N/A
0N/A byte[] Ke = null;
0N/A byte[] Ki = null;
0N/A
0N/A try {
0N/A // Derive encryption key
0N/A byte[] constant = new byte[5];
0N/A constant[0] = (byte) ((usage>>24)&0xff);
0N/A constant[1] = (byte) ((usage>>16)&0xff);
0N/A constant[2] = (byte) ((usage>>8)&0xff);
0N/A constant[3] = (byte) (usage&0xff);
0N/A
0N/A constant[4] = (byte) 0xaa;
0N/A
0N/A Ke = dk(baseKey, constant); // Encryption key
0N/A
0N/A if (debug) {
0N/A System.err.println("usage: " + usage);
0N/A if (ivec != null) {
0N/A traceOutput("old_state.ivec", ivec, 0, ivec.length);
0N/A }
0N/A traceOutput("ciphertext", ciphertext, start, Math.min(len, 32));
0N/A traceOutput("constant", constant, 0, constant.length);
0N/A traceOutput("baseKey", baseKey, 0, baseKey.length);
0N/A traceOutput("Ke", Ke, 0, Ke.length);
0N/A }
0N/A
0N/A Cipher decCipher = getCipher(Ke, ivec, Cipher.DECRYPT_MODE);
0N/A int blockSize = decCipher.getBlockSize();
0N/A
0N/A // Decrypt [confounder | plaintext | padding] (without checksum)
0N/A int cksumSize = getChecksumLength();
0N/A int cipherSize = len - cksumSize;
0N/A byte[] decrypted = decCipher.doFinal(ciphertext, start, cipherSize);
0N/A
0N/A if (debug) {
0N/A traceOutput("decrypted", decrypted, 0,
0N/A Math.min(decrypted.length, 32));
0N/A }
0N/A
0N/A // decrypted = [confounder | plaintext | padding]
0N/A
0N/A // Derive integrity key
0N/A constant[4] = (byte) 0x55;
0N/A Ki = dk(baseKey, constant); // Integrity key
0N/A if (debug) {
0N/A traceOutput("constant", constant, 0, constant.length);
0N/A traceOutput("Ki", Ki, 0, Ke.length);
0N/A }
0N/A
0N/A // Verify checksum
0N/A // H1 = HMAC(Ki, conf | plaintext | pad)
0N/A byte[] calculatedHmac = getHmac(Ki, decrypted);
0N/A
0N/A if (debug) {
0N/A traceOutput("calculated Hmac", calculatedHmac, 0,
0N/A calculatedHmac.length);
0N/A traceOutput("message Hmac", ciphertext, cipherSize,
0N/A cksumSize);
0N/A }
0N/A
0N/A boolean cksumFailed = false;
0N/A if (calculatedHmac.length >= cksumSize) {
0N/A for (int i = 0; i < cksumSize; i++) {
0N/A if (calculatedHmac[i] != ciphertext[cipherSize+i]) {
0N/A cksumFailed = true;
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A
0N/A if (cksumFailed) {
0N/A throw new GeneralSecurityException("Checksum failed");
0N/A }
0N/A
0N/A // Prepare decrypted msg and ivec to be returned
0N/A // Last blockSize bytes of ciphertext without checksum
0N/A if (ivec != null && ivec.length == blockSize) {
0N/A System.arraycopy(ciphertext, start + cipherSize - blockSize,
0N/A ivec, 0, blockSize);
0N/A if (debug) {
0N/A traceOutput("new_state.ivec", ivec, 0, ivec.length);
0N/A }
0N/A }
0N/A
0N/A // Get rid of confounder
0N/A // [plaintext | padding]
0N/A byte[] plaintext = new byte[decrypted.length - blockSize];
0N/A System.arraycopy(decrypted, blockSize, plaintext,
0N/A 0, plaintext.length);
0N/A return plaintext; // padding still there
0N/A } finally {
0N/A if (Ke != null) {
0N/A Arrays.fill(Ke, 0, Ke.length, (byte) 0);
0N/A }
0N/A if (Ki != null) {
0N/A Arrays.fill(Ki, 0, Ki.length, (byte) 0);
0N/A }
0N/A }
0N/A }
0N/A
0N/A // Round up to the next blocksize
0N/A int roundup(int n, int blocksize) {
0N/A return (((n + blocksize - 1) / blocksize) * blocksize);
0N/A }
0N/A
0N/A public byte[] calculateChecksum(byte[] baseKey, int usage, byte[] input,
0N/A int start, int len) throws GeneralSecurityException {
0N/A
0N/A if (!KeyUsage.isValid(usage)) {
0N/A throw new GeneralSecurityException("Invalid key usage number: "
0N/A + usage);
0N/A }
0N/A
0N/A // Derive keys
0N/A byte[] constant = new byte[5];
0N/A constant[0] = (byte) ((usage>>24)&0xff);
0N/A constant[1] = (byte) ((usage>>16)&0xff);
0N/A constant[2] = (byte) ((usage>>8)&0xff);
0N/A constant[3] = (byte) (usage&0xff);
0N/A
0N/A constant[4] = (byte) 0x99;
0N/A
0N/A byte[] Kc = dk(baseKey, constant); // Checksum key
0N/A if (debug) {
0N/A System.err.println("usage: " + usage);
0N/A traceOutput("input", input, start, Math.min(len, 32));
0N/A traceOutput("constant", constant, 0, constant.length);
0N/A traceOutput("baseKey", baseKey, 0, baseKey.length);
0N/A traceOutput("Kc", Kc, 0, Kc.length);
0N/A }
0N/A
0N/A try {
0N/A // Generate checksum
0N/A // H1 = HMAC(Kc, input)
0N/A byte[] hmac = getHmac(Kc, input);
0N/A if (debug) {
0N/A traceOutput("hmac", hmac, 0, hmac.length);
0N/A }
0N/A if (hmac.length == getChecksumLength()) {
0N/A return hmac;
0N/A } else if (hmac.length > getChecksumLength()) {
0N/A byte[] buf = new byte[getChecksumLength()];
0N/A System.arraycopy(hmac, 0, buf, 0, buf.length);
0N/A return buf;
0N/A } else {
0N/A throw new GeneralSecurityException("checksum size too short: " +
0N/A hmac.length + "; expecting : " + getChecksumLength());
0N/A }
0N/A } finally {
0N/A Arrays.fill(Kc, 0, Kc.length, (byte)0);
0N/A }
0N/A }
0N/A
0N/A // DK(Key, Constant) = random-to-key(DR(Key, Constant))
0N/A byte[] dk(byte[] key, byte[] constant)
0N/A throws GeneralSecurityException {
0N/A return randomToKey(dr(key, constant));
0N/A }
0N/A
0N/A /*
0N/A * From RFC 3961.
0N/A *
0N/A * DR(Key, Constant) = k-truncate(E(Key, Constant,
0N/A * initial-cipher-state))
0N/A *
0N/A * Here DR is the random-octet generation function described below, and
0N/A * DK is the key-derivation function produced from it. In this
0N/A * construction, E(Key, Plaintext, CipherState) is a cipher, Constant is
0N/A * a well-known constant determined by the specific usage of this
0N/A * function, and k-truncate truncates its argument by taking the first k
0N/A * bits. Here, k is the key generation seed length needed for the
0N/A * encryption system.
0N/A *
0N/A * The output of the DR function is a string of bits; the actual key is
0N/A * produced by applying the cryptosystem's random-to-key operation on
0N/A * this bitstring.
0N/A *
0N/A * If the Constant is smaller than the cipher block size of E, then it
0N/A * must be expanded with n-fold() so it can be encrypted. If the output
0N/A * of E is shorter than k bits it is fed back into the encryption as
0N/A * many times as necessary. The construct is as follows (where |
0N/A * indicates concatentation):
0N/A *
0N/A * K1 = E(Key, n-fold(Constant), initial-cipher-state)
0N/A * K2 = E(Key, K1, initial-cipher-state)
0N/A * K3 = E(Key, K2, initial-cipher-state)
0N/A * K4 = ...
0N/A *
0N/A * DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)
0N/A */
0N/A private byte[] dr(byte[] key, byte[] constant)
0N/A throws GeneralSecurityException {
0N/A
0N/A Cipher encCipher = getCipher(key, null, Cipher.ENCRYPT_MODE);
0N/A int blocksize = encCipher.getBlockSize();
0N/A
0N/A if (constant.length != blocksize) {
0N/A constant = nfold(constant, blocksize * 8);
0N/A }
0N/A byte[] toBeEncrypted = constant;
0N/A
0N/A int keybytes = (getKeySeedLength()>>3); // from bits to bytes
0N/A byte[] rawkey = new byte[keybytes];
0N/A int posn = 0;
0N/A
0N/A /* loop encrypting the blocks until enough key bytes are generated */
0N/A int n = 0, len;
0N/A while (n < keybytes) {
0N/A if (debug) {
0N/A System.err.println("Encrypting: " +
0N/A bytesToString(toBeEncrypted));
0N/A }
0N/A
0N/A byte[] cipherBlock = encCipher.doFinal(toBeEncrypted);
0N/A if (debug) {
0N/A System.err.println("K: " + ++posn + " = " +
0N/A bytesToString(cipherBlock));
0N/A }
0N/A
0N/A len = (keybytes - n <= cipherBlock.length ? (keybytes - n) :
0N/A cipherBlock.length);
0N/A if (debug) {
0N/A System.err.println("copying " + len + " key bytes");
0N/A }
0N/A System.arraycopy(cipherBlock, 0, rawkey, n, len);
0N/A n += len;
0N/A toBeEncrypted = cipherBlock;
0N/A }
0N/A return rawkey;
0N/A }
0N/A
0N/A// ---------------------------------
0N/A
0N/A // From MIT-1.3.1 distribution
0N/A /*
0N/A * n-fold(k-bits):
0N/A * l = lcm(n,k)
0N/A * r = l/k
0N/A * s = k-bits | k-bits rot 13 | k-bits rot 13*2 | ... | k-bits rot 13*(r-1)
0N/A * compute the 1's complement sum:
0N/A * n-fold = s[0..n-1]+s[n..2n-1]+s[2n..3n-1]+..+s[(k-1)*n..k*n-1]
0N/A */
0N/A
0N/A /*
0N/A * representation: msb first, assume n and k are multiples of 8, and
0N/A * that k>=16. this is the case of all the cryptosystems which are
0N/A * likely to be used. this function can be replaced if that
0N/A * assumption ever fails.
0N/A */
0N/A
0N/A /* input length is in bits */
0N/A static byte[] nfold(byte[] in, int outbits) {
0N/A
0N/A int inbits = in.length;
0N/A outbits >>= 3; // count in bytes
0N/A
0N/A /* first compute lcm(n,k) */
0N/A int a, b, c, lcm;
0N/A a = outbits; // n
0N/A b = inbits; // k
0N/A
0N/A while (b != 0) {
0N/A c = b;
0N/A b = a % b;
0N/A a = c;
0N/A }
0N/A lcm = outbits*inbits/a;
0N/A
0N/A if (debug) {
0N/A System.err.println("k: " + inbits);
0N/A System.err.println("n: " + outbits);
0N/A System.err.println("lcm: " + lcm);
0N/A }
0N/A
0N/A /* now do the real work */
0N/A byte[] out = new byte[outbits];
0N/A Arrays.fill(out, (byte)0);
0N/A
0N/A int thisbyte = 0;
0N/A int msbit, i, bval, oval;
0N/A
0N/A // this will end up cycling through k lcm(k,n)/k times, which
0N/A // is correct
0N/A for (i = lcm-1; i >= 0; i--) {
0N/A /* compute the msbit in k which gets added into this byte */
0N/A msbit = (/* first, start with msbit in the first, unrotated byte */
0N/A ((inbits<<3)-1)
0N/A /* then, for each byte, shift to right for each repetition */
0N/A + (((inbits<<3)+13)*(i/inbits))
0N/A /* last, pick out correct byte within that shifted repetition */
0N/A + ((inbits-(i%inbits)) << 3)) % (inbits << 3);
0N/A
0N/A /* pull out the byte value itself */
0N/A // Mask off values using &0xff to get only the lower byte
0N/A // Use >>> to avoid sign extension
0N/A bval = ((((in[((inbits-1)-(msbit>>>3))%inbits]&0xff)<<8)|
0N/A (in[((inbits)-(msbit>>>3))%inbits]&0xff))
0N/A >>>((msbit&7)+1))&0xff;
0N/A
0N/A /*
0N/A System.err.println("((" +
0N/A ((in[((inbits-1)-(msbit>>>3))%inbits]&0xff)<<8)
0N/A + "|" + (in[((inbits)-(msbit>>>3))%inbits]&0xff) + ")"
0N/A + ">>>" + ((msbit&7)+1) + ")&0xff = " + bval);
0N/A */
0N/A
0N/A thisbyte += bval;
0N/A
0N/A /* do the addition */
0N/A // Mask off values using &0xff to get only the lower byte
0N/A oval = (out[i%outbits]&0xff);
0N/A thisbyte += oval;
0N/A out[i%outbits] = (byte) (thisbyte&0xff);
0N/A
0N/A if (debug) {
0N/A System.err.println("msbit[" + i + "] = " + msbit + "\tbval=" +
0N/A Integer.toHexString(bval) + "\toval=" +
0N/A Integer.toHexString(oval)
0N/A + "\tsum = " + Integer.toHexString(thisbyte));
0N/A }
0N/A
0N/A
0N/A /* keep around the carry bit, if any */
0N/A thisbyte >>>= 8;
0N/A
0N/A if (debug) {
0N/A System.err.println("carry=" + thisbyte);
0N/A }
0N/A }
0N/A
0N/A /* if there's a carry bit left over, add it back in */
0N/A if (thisbyte != 0) {
0N/A for (i = outbits-1; i >= 0; i--) {
0N/A /* do the addition */
0N/A thisbyte += (out[i]&0xff);
0N/A out[i] = (byte) (thisbyte&0xff);
0N/A
0N/A /* keep around the carry bit, if any */
0N/A thisbyte >>>= 8;
0N/A }
0N/A }
0N/A
0N/A return out;
0N/A }
0N/A
0N/A // Routines used for debugging
0N/A static String bytesToString(byte[] digest) {
0N/A // Get character representation of digest
0N/A StringBuffer digestString = new StringBuffer();
0N/A
0N/A for (int i = 0; i < digest.length; i++) {
0N/A if ((digest[i] & 0x000000ff) < 0x10) {
0N/A digestString.append("0" +
0N/A Integer.toHexString(digest[i] & 0x000000ff));
0N/A } else {
0N/A digestString.append(
0N/A Integer.toHexString(digest[i] & 0x000000ff));
0N/A }
0N/A }
0N/A return digestString.toString();
0N/A }
0N/A
0N/A private static byte[] binaryStringToBytes(String str) {
0N/A char[] usageStr = str.toCharArray();
0N/A byte[] usage = new byte[usageStr.length/2];
0N/A for (int i = 0; i < usage.length; i++) {
0N/A byte a = Byte.parseByte(new String(usageStr, i*2, 1), 16);
0N/A byte b = Byte.parseByte(new String(usageStr, i*2 + 1, 1), 16);
0N/A usage[i] = (byte) ((a<<4)|b);
0N/A }
0N/A return usage;
0N/A }
0N/A
0N/A static void traceOutput(String traceTag, byte[] output, int offset,
0N/A int len) {
0N/A try {
0N/A ByteArrayOutputStream out = new ByteArrayOutputStream(len);
0N/A new HexDumpEncoder().encodeBuffer(
0N/A new ByteArrayInputStream(output, offset, len), out);
0N/A
0N/A System.err.println(traceTag + ":" + out.toString());
0N/A } catch (Exception e) {
0N/A }
0N/A }
0N/A
0N/A// String.getBytes("UTF-8");
0N/A// Do this instead of using String to avoid making password immutable
0N/A static byte[] charToUtf8(char[] chars) {
0N/A Charset utf8 = Charset.forName("UTF-8");
0N/A
0N/A CharBuffer cb = CharBuffer.wrap(chars);
0N/A ByteBuffer bb = utf8.encode(cb);
0N/A int len = bb.limit();
0N/A byte[] answer = new byte[len];
0N/A bb.get(answer, 0, len);
0N/A return answer;
0N/A }
0N/A
0N/A static byte[] charToUtf16(char[] chars) {
0N/A Charset utf8 = Charset.forName("UTF-16LE");
0N/A
0N/A CharBuffer cb = CharBuffer.wrap(chars);
0N/A ByteBuffer bb = utf8.encode(cb);
0N/A int len = bb.limit();
0N/A byte[] answer = new byte[len];
0N/A bb.get(answer, 0, len);
0N/A return answer;
0N/A }
0N/A}