/*
*/
/*
* Copyright (C) 1998 by the FundsXpress, INC.
*
* All rights reserved.
*
* Export of this software from the United States of America may require
* a specific license from the United States Government. It is the
* responsibility of any person or organization contemplating export to
* obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of FundsXpress. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. FundsXpress makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/**
* Implements Derive Key cryptography functionality as defined in RFC 3961.
*
* This is an abstract class. Concrete subclasses need to implement
* the abstract methods.
*/
public abstract class DkCrypto {
protected static final boolean debug = false;
// These values correspond to the ASCII encoding for the string "kerberos"
static final byte[] KERBEROS_CONSTANT =
{0x6b, 0x65, 0x72, 0x62, 0x65, 0x72, 0x6f, 0x73};
throws GeneralSecurityException;
throws GeneralSecurityException;
/**
* From RFC 3961.
*
* encryption function conf = random string of length c
* pad = shortest string to bring confounder
* and plaintext to a length that's a
* multiple of m
* (C1, newIV) = E(Ke, conf | plaintext | pad,
* oldstate.ivec)
* H1 = HMAC(Ki, conf | plaintext | pad)
* ciphertext = C1 | H1[1..h]
* newstate.ivec = newIV
*
* @param ivec initial vector to use when initializing the cipher; if null,
* then blocksize number of zeros are used,
* @param new_ivec if non-null, it is updated upon return to be the
* new ivec to use when calling encrypt next time
*/
throws GeneralSecurityException, KrbCryptoException {
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
try {
// Derive encryption key
byte[] constant = new byte[5];
if (debug) {
}
}
// Encrypt
// C1 = E(Ke, conf | plaintext | pad, oldivec)
if (debug) {
}
byte[] toBeEncrypted = new byte[plainSize];
// Set padding bytes to zero
(byte)0);
byte[] ciphertext = new byte[ccSize];
// Update ivec for next operation
// (last blockSize bytes of ciphertext)
// newstate.ivec = newIV
if (debug) {
}
}
// Derive integrity key
if (debug) {
}
// Generate checksum
// H1 = HMAC(Ki, conf | plaintext | pad)
if (debug) {
}
// C1 | H1[1..h]
return ciphertext;
} finally {
}
}
}
}
/**
* Performs encryption using given key only; does not add
* confounder, padding, or checksum. Incoming data to be encrypted
* assumed to have the correct blocksize.
* Ignore key usage.
*/
throws GeneralSecurityException, KrbCryptoException {
if (debug) {
}
}
// Encrypt
throw new GeneralSecurityException(
"length of data to be encrypted (" + len +
}
byte[] ciphertext = new byte[cipherSize];
return ciphertext;
}
/**
* Decrypts data using specified key and initial vector.
* @param baseKey encryption key to use
* @param ciphertext encrypted data to be decrypted
* @param usage ignored
*/
throws GeneralSecurityException {
if (debug) {
}
}
throw new GeneralSecurityException(
"length of data to be decrypted (" + len +
}
if (debug) {
}
return decrypted;
}
/**
* @param baseKey key from which keys are to be derived using usage
* @param ciphertext E(Ke, conf | plaintext | padding, ivec) | H1[1..h]
*/
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
try {
// Derive encryption key
byte[] constant = new byte[5];
if (debug) {
}
}
// Decrypt [confounder | plaintext | padding] (without checksum)
int cksumSize = getChecksumLength();
if (debug) {
}
// decrypted = [confounder | plaintext | padding]
// Derive integrity key
if (debug) {
}
// Verify checksum
// H1 = HMAC(Ki, conf | plaintext | pad)
if (debug) {
}
boolean cksumFailed = false;
for (int i = 0; i < cksumSize; i++) {
cksumFailed = true;
break;
}
}
}
if (cksumFailed) {
throw new GeneralSecurityException("Checksum failed");
}
// Prepare decrypted msg and ivec to be returned
// Last blockSize bytes of ciphertext without checksum
if (debug) {
}
}
// Get rid of confounder
// [plaintext | padding]
return plaintext; // padding still there
} finally {
}
}
}
}
// Round up to the next blocksize
}
throw new GeneralSecurityException("Invalid key usage number: "
+ usage);
}
// Derive keys
byte[] constant = new byte[5];
if (debug) {
}
try {
// Generate checksum
// H1 = HMAC(Kc, input)
if (debug) {
}
return hmac;
byte[] buf = new byte[getChecksumLength()];
return buf;
} else {
throw new GeneralSecurityException("checksum size too short: " +
}
} finally {
}
}
// DK(Key, Constant) = random-to-key(DR(Key, Constant))
throws GeneralSecurityException {
}
/*
* From RFC 3961.
*
* DR(Key, Constant) = k-truncate(E(Key, Constant,
* initial-cipher-state))
*
* Here DR is the random-octet generation function described below, and
* DK is the key-derivation function produced from it. In this
* construction, E(Key, Plaintext, CipherState) is a cipher, Constant is
* a well-known constant determined by the specific usage of this
* function, and k-truncate truncates its argument by taking the first k
* bits. Here, k is the key generation seed length needed for the
* encryption system.
*
* The output of the DR function is a string of bits; the actual key is
* produced by applying the cryptosystem's random-to-key operation on
* this bitstring.
*
* If the Constant is smaller than the cipher block size of E, then it
* must be expanded with n-fold() so it can be encrypted. If the output
* of E is shorter than k bits it is fed back into the encryption as
* many times as necessary. The construct is as follows (where |
* indicates concatentation):
*
* K1 = E(Key, n-fold(Constant), initial-cipher-state)
* K2 = E(Key, K1, initial-cipher-state)
* K3 = E(Key, K2, initial-cipher-state)
* K4 = ...
*
* DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)
*/
throws GeneralSecurityException {
}
byte[] toBeEncrypted = constant;
int posn = 0;
/* loop encrypting the blocks until enough key bytes are generated */
int n = 0, len;
while (n < keybytes) {
if (debug) {
}
if (debug) {
}
if (debug) {
}
n += len;
}
return rawkey;
}
// ---------------------------------
// From MIT-1.3.1 distribution
/*
* n-fold(k-bits):
* l = lcm(n,k)
* r = l/k
* s = k-bits | k-bits rot 13 | k-bits rot 13*2 | ... | k-bits rot 13*(r-1)
* compute the 1's complement sum:
* n-fold = s[0..n-1]+s[n..2n-1]+s[2n..3n-1]+..+s[(k-1)*n..k*n-1]
*/
/*
* representation: msb first, assume n and k are multiples of 8, and
* that k>=16. this is the case of all the cryptosystems which are
* likely to be used. this function can be replaced if that
* assumption ever fails.
*/
/* input length is in bits */
/* first compute lcm(n,k) */
int a, b, c, lcm;
a = outbits; // n
b = inbits; // k
while (b != 0) {
c = b;
b = a % b;
a = c;
}
if (debug) {
}
/* now do the real work */
int thisbyte = 0;
// this will end up cycling through k lcm(k,n)/k times, which
// is correct
/* compute the msbit in k which gets added into this byte */
msbit = (/* first, start with msbit in the first, unrotated byte */
/* then, for each byte, shift to right for each repetition */
/* last, pick out correct byte within that shifted repetition */
/* pull out the byte value itself */
// Mask off values using &0xff to get only the lower byte
// Use >>> to avoid sign extension
/*
System.err.println("((" +
((in[((inbits-1)-(msbit>>>3))%inbits]&0xff)<<8)
+ "|" + (in[((inbits)-(msbit>>>3))%inbits]&0xff) + ")"
+ ">>>" + ((msbit&7)+1) + ")&0xff = " + bval);
*/
/* do the addition */
// Mask off values using &0xff to get only the lower byte
if (debug) {
}
/* keep around the carry bit, if any */
thisbyte >>>= 8;
if (debug) {
}
}
/* if there's a carry bit left over, add it back in */
if (thisbyte != 0) {
/* do the addition */
/* keep around the carry bit, if any */
thisbyte >>>= 8;
}
}
return out;
}
// Routines used for debugging
// Get character representation of digest
} else {
}
}
return digestString.toString();
}
usage[i] = (byte) ((a<<4)|b);
}
return usage;
}
int len) {
try {
new HexDumpEncoder().encodeBuffer(
} catch (Exception e) {
}
}
// String.getBytes("UTF-8");
// Do this instead of using String to avoid making password immutable
return answer;
}
return answer;
}
}