下面列出了javax.crypto.Mac#getMacLength ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public Identity decode(final byte[] bytes) throws IOException {
final Mac mac = this.mac();
if (bytes.length < mac.getMacLength()) {
throw new IOException("Invalid data size");
}
final byte[] signature = new byte[mac.getMacLength()];
final byte[] encoded = new byte[bytes.length - signature.length];
System.arraycopy(bytes, 0, encoded, 0, encoded.length);
System.arraycopy(
bytes,
encoded.length,
signature,
0,
signature.length
);
final byte[] actual = mac.doFinal(encoded);
if (!Arrays.equals(actual, signature)) {
throw new IOException("Bad signature");
}
return this.cdc.decode(encoded);
}
/**
* Initializes this Hkdf with input keying material and a salt. If <code>
* salt</code> is <code>null</code> or of length 0, then a default salt of
* HashLen zeros will be used (where HashLen is the length of the return
* value of the supplied algorithm).
*
* @param salt
* the salt used for key extraction (optional)
* @param ikm
* the Input Keying Material
*/
public void init(final byte[] ikm, final byte[] salt) {
byte[] realSalt = (salt == null) ? EMPTY_ARRAY : salt.clone();
byte[] rawKeyMaterial = EMPTY_ARRAY;
try {
Mac extractionMac = Mac.getInstance(algorithm, provider);
if (realSalt.length == 0) {
realSalt = new byte[extractionMac.getMacLength()];
Arrays.fill(realSalt, (byte) 0);
}
extractionMac.init(new SecretKeySpec(realSalt, algorithm));
rawKeyMaterial = extractionMac.doFinal(ikm);
SecretKeySpec key = new SecretKeySpec(rawKeyMaterial, algorithm);
Arrays.fill(rawKeyMaterial, (byte) 0); // Zeroize temporary array
unsafeInitWithoutKeyExtraction(key);
} catch (GeneralSecurityException e) {
// We've already checked all of the parameters so no exceptions
// should be possible here.
throw new RuntimeException("Unexpected exception", e);
} finally {
Arrays.fill(rawKeyMaterial, (byte) 0); // Zeroize temporary array
}
}
private static void verifyMac(InputStream inputStream, long length, Mac mac, byte[] theirDigest)
throws InvalidMacException
{
try {
MessageDigest digest = MessageDigest.getInstance("SHA256");
int remainingData = Util.toIntExact(length) - mac.getMacLength();
byte[] buffer = new byte[4096];
while (remainingData > 0) {
int read = inputStream.read(buffer, 0, Math.min(buffer.length, remainingData));
mac.update(buffer, 0, read);
digest.update(buffer, 0, read);
remainingData -= read;
}
byte[] ourMac = mac.doFinal();
byte[] theirMac = new byte[mac.getMacLength()];
Util.readFully(inputStream, theirMac);
if (!MessageDigest.isEqual(ourMac, theirMac)) {
throw new InvalidMacException("MAC doesn't match!");
}
byte[] ourDigest = digest.digest(theirMac);
if (theirDigest != null && !MessageDigest.isEqual(ourDigest, theirDigest)) {
throw new InvalidMacException("Digest doesn't match!");
}
} catch (IOException | ArithmeticException e1) {
throw new InvalidMacException(e1);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
/**
* Implementation of PBKDF2 (RFC2898).
*
* @param mac the pre-initialized {@link Mac} instance to use
* @param s the salt
* @param c the iteration count
* @param dk the byte array that derived key will be placed in
* @param dkLen the intended length, in octets, of the derived key
* @throws GeneralSecurityException if the key length is too long
*/
private static void pbkdf2(Mac mac, byte[] s, int c, byte[] dk, int dkLen) throws GeneralSecurityException {
int hLen = mac.getMacLength();
if (dkLen > (Math.pow(2, 32) - 1) * hLen) {
throw new GeneralSecurityException("Requested key length too long");
}
byte[] U = new byte[hLen];
byte[] T = new byte[hLen];
byte[] block1 = new byte[s.length + 4];
int l = (int) Math.ceil((double) dkLen / hLen);
int r = dkLen - (l - 1) * hLen;
arraycopy(s, 0, block1, 0, s.length);
for (int i = 1; i <= l; i++) {
block1[s.length + 0] = (byte) (i >> 24 & 0xff);
block1[s.length + 1] = (byte) (i >> 16 & 0xff);
block1[s.length + 2] = (byte) (i >> 8 & 0xff);
block1[s.length + 3] = (byte) (i >> 0 & 0xff);
mac.update(block1);
mac.doFinal(U, 0);
arraycopy(U, 0, T, 0, hLen);
for (int j = 1; j < c; j++) {
mac.update(U);
mac.doFinal(U, 0);
for (int k = 0; k < hLen; k++) {
T[k] ^= U[k];
}
}
arraycopy(T, 0, dk, (i - 1) * hLen, (i == l ? r : hLen));
}
}
private static void verifyMac(File file, Mac mac, byte[] theirDigest)
throws FileNotFoundException, InvalidMacException
{
try {
MessageDigest digest = MessageDigest.getInstance("SHA256");
FileInputStream fin = new FileInputStream(file);
int remainingData = Util.toIntExact(file.length()) - mac.getMacLength();
byte[] buffer = new byte[4096];
while (remainingData > 0) {
int read = fin.read(buffer, 0, Math.min(buffer.length, remainingData));
mac.update(buffer, 0, read);
digest.update(buffer, 0, read);
remainingData -= read;
}
byte[] ourMac = mac.doFinal();
byte[] theirMac = new byte[mac.getMacLength()];
Util.readFully(fin, theirMac);
if (!MessageDigest.isEqual(ourMac, theirMac)) {
throw new InvalidMacException("MAC doesn't match!");
}
byte[] ourDigest = digest.digest(theirMac);
if (!MessageDigest.isEqual(ourDigest, theirDigest)) {
throw new InvalidMacException("Digest doesn't match!");
}
} catch (IOException | ArithmeticException e1) {
throw new InvalidMacException(e1);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
private static byte[] verifyMac(byte[] macSalt, int iterations, byte[] encryptedAndMacdData, String passphrase) throws InvalidPassphraseException, GeneralSecurityException, IOException {
Mac hmac = getMacForPassphrase(passphrase, macSalt, iterations);
byte[] encryptedData = new byte[encryptedAndMacdData.length - hmac.getMacLength()];
System.arraycopy(encryptedAndMacdData, 0, encryptedData, 0, encryptedData.length);
byte[] givenMac = new byte[hmac.getMacLength()];
System.arraycopy(encryptedAndMacdData, encryptedAndMacdData.length - hmac.getMacLength(), givenMac, 0, givenMac.length);
byte[] localMac = hmac.doFinal(encryptedData);
if (Arrays.equals(givenMac, localMac)) return encryptedData;
else throw new InvalidPassphraseException("MAC Error");
}
/**
* Implementation of PBKDF2 (RFC2898).
*
* @param mac Pre-initialized {@link Mac} instance to use.
* @param S Salt.
* @param c Iteration count.
* @param DK Byte array that derived key will be placed in.
* @param dkLen Intended length, in octets, of the derived key.
*
* @throws GeneralSecurityException
*/
public static void pbkdf2(Mac mac, byte[] S, int c, byte[] DK, int dkLen) throws GeneralSecurityException {
int hLen = mac.getMacLength();
if (dkLen > (Math.pow(2, 32) - 1) * hLen) {
throw new GeneralSecurityException("Requested key length too long");
}
byte[] U = new byte[hLen];
byte[] T = new byte[hLen];
byte[] block1 = new byte[S.length + 4];
int l = (int) Math.ceil((double) dkLen / hLen);
int r = dkLen - (l - 1) * hLen;
arraycopy(S, 0, block1, 0, S.length);
for (int i = 1; i <= l; i++) {
block1[S.length + 0] = (byte) (i >> 24 & 0xff);
block1[S.length + 1] = (byte) (i >> 16 & 0xff);
block1[S.length + 2] = (byte) (i >> 8 & 0xff);
block1[S.length + 3] = (byte) (i >> 0 & 0xff);
mac.update(block1);
mac.doFinal(U, 0);
arraycopy(U, 0, T, 0, hLen);
for (int j = 1; j < c; j++) {
mac.update(U);
mac.doFinal(U, 0);
for (int k = 0; k < hLen; k++) {
T[k] ^= U[k];
}
}
arraycopy(T, 0, DK, (i - 1) * hLen, (i == l ? r : hLen));
}
}
public static byte[] deriveKey( byte[] password, byte[] salt, int iterationCount, int dkLen )
throws java.security.NoSuchAlgorithmException, java.security.InvalidKeyException
{
SecretKeySpec keyspec = new SecretKeySpec( password, "HmacSHA256" );
Mac prf = Mac.getInstance( "HmacSHA256" );
prf.init( keyspec );
// Note: hLen, dkLen, l, r, T, F, etc. are horrible names for
// variables and functions in this day and age, but they
// reflect the terse symbols used in RFC 2898 to describe
// the PBKDF2 algorithm, which improves validation of the
// code vs. the RFC.
//
// dklen is expressed in bytes. (16 for a 128-bit key)
int hLen = prf.getMacLength(); // 20 for SHA1
int l = Math.max( dkLen, hLen); // 1 for 128bit (16-byte) keys
int r = dkLen - (l-1)*hLen; // 16 for 128bit (16-byte) keys
byte T[] = new byte[l * hLen];
int ti_offset = 0;
for (int i = 1; i <= l; i++) {
F( T, ti_offset, prf, salt, iterationCount, i );
ti_offset += hLen;
}
if (r < hLen) {
// Incomplete last block
byte DK[] = new byte[dkLen];
System.arraycopy(T, 0, DK, 0, dkLen);
return DK;
}
return T;
}
private static byte[] verifyMac(byte[] macSalt, int iterations, byte[] encryptedAndMacdData, String passphrase) throws InvalidPassphraseException, GeneralSecurityException, IOException {
Mac hmac = getMacForPassphrase(passphrase, macSalt, iterations);
byte[] encryptedData = new byte[encryptedAndMacdData.length - hmac.getMacLength()];
System.arraycopy(encryptedAndMacdData, 0, encryptedData, 0, encryptedData.length);
byte[] givenMac = new byte[hmac.getMacLength()];
System.arraycopy(encryptedAndMacdData, encryptedAndMacdData.length-hmac.getMacLength(), givenMac, 0, givenMac.length);
byte[] localMac = hmac.doFinal(encryptedData);
if (Arrays.equals(givenMac, localMac)) return encryptedData;
else throw new InvalidPassphraseException("MAC Error");
}
/**
* Implementation of PBKDF2 (RFC2898).
*
* @param mac the pre-initialized {@link Mac} instance to use
* @param s the salt
* @param c the iteration count
* @param dk the byte array that derived key will be placed in
* @param dkLen the intended length, in octets, of the derived key
* @throws GeneralSecurityException if the key length is too long
*/
private static void pbkdf2(Mac mac, byte[] s, int c, byte[] dk, int dkLen) throws GeneralSecurityException {
int hLen = mac.getMacLength();
if (dkLen > (Math.pow(2, 32) - 1) * hLen) {
throw new GeneralSecurityException("Requested key length too long");
}
byte[] U = new byte[hLen];
byte[] T = new byte[hLen];
byte[] block1 = new byte[s.length + 4];
int l = (int) Math.ceil((double) dkLen / hLen);
int r = dkLen - (l - 1) * hLen;
arraycopy(s, 0, block1, 0, s.length);
for (int i = 1; i <= l; i++) {
block1[s.length + 0] = (byte) (i >> 24 & 0xff);
block1[s.length + 1] = (byte) (i >> 16 & 0xff);
block1[s.length + 2] = (byte) (i >> 8 & 0xff);
block1[s.length + 3] = (byte) (i >> 0 & 0xff);
mac.update(block1);
mac.doFinal(U, 0);
arraycopy(U, 0, T, 0, hLen);
for (int j = 1; j < c; j++) {
mac.update(U);
mac.doFinal(U, 0);
for (int k = 0; k < hLen; k++) {
T[k] ^= U[k];
}
}
arraycopy(T, 0, dk, (i - 1) * hLen, (i == l ? r : hLen));
}
}
private static byte[] deriveKey(byte[] password, byte[] salt, int iterationCount, int dkLen)
throws NoSuchAlgorithmException, InvalidKeyException {
SecretKeySpec keyspec = new SecretKeySpec(password, "HmacSHA256");
Mac prf = Mac.getInstance("HmacSHA256");
prf.init(keyspec);
// Note: hLen, dkLen, l, r, T, F, etc. are horrible names for
// variables and functions in this day and age, but they
// reflect the terse symbols used in RFC 2898 to describe
// the PBKDF2 algorithm, which improves validation of the
// code vs. the RFC.
//
// dklen is expressed in bytes. (16 for a 128-bit key)
int hLen = prf.getMacLength(); // 20 for SHA1
int l = Math.max(dkLen, hLen); // 1 for 128bit (16-byte) keys
int r = dkLen - (l - 1) * hLen; // 16 for 128bit (16-byte) keys
byte T[] = new byte[l * hLen];
int ti_offset = 0;
for (int i = 1; i <= l; i++) {
F(T, ti_offset, prf, salt, iterationCount, i);
ti_offset += hLen;
}
if (r < hLen) {
// Incomplete last block
byte DK[] = new byte[dkLen];
System.arraycopy(T, 0, DK, 0, dkLen);
return DK;
}
return T;
}
private static void F(byte[] dest, int offset, Mac prf, byte[] S, int c, int blockIndex) {
final int hLen = prf.getMacLength();
byte U_r[] = new byte[hLen];
// U0 = S || INT (i);
byte U_i[] = new byte[S.length + 4];
System.arraycopy(S, 0, U_i, 0, S.length);
INT(U_i, S.length, blockIndex);
for (int i = 0; i < c; i++) {
U_i = prf.doFinal(U_i);
xor(U_r, U_i);
}
System.arraycopy(U_r, 0, dest, offset, hLen);
}
private void verifyMac(File file, Mac mac, Optional<byte[]> theirDigest)
throws FileNotFoundException, InvalidMacException
{
try {
MessageDigest digest = MessageDigest.getInstance("SHA256");
FileInputStream fin = new FileInputStream(file);
int remainingData = Util.toIntExact(file.length()) - mac.getMacLength();
byte[] buffer = new byte[4096];
while (remainingData > 0) {
int read = fin.read(buffer, 0, Math.min(buffer.length, remainingData));
mac.update(buffer, 0, read);
digest.update(buffer, 0, read);
remainingData -= read;
}
byte[] ourMac = mac.doFinal();
byte[] theirMac = new byte[mac.getMacLength()];
Util.readFully(fin, theirMac);
if (!MessageDigest.isEqual(ourMac, theirMac)) {
throw new InvalidMacException("MAC doesn't match!");
}
byte[] ourDigest = digest.digest(theirMac);
if (theirDigest.isPresent() && !MessageDigest.isEqual(ourDigest, theirDigest.get())) {
throw new InvalidMacException("Digest doesn't match!");
}
} catch (IOException | ArithmeticException e1) {
throw new InvalidMacException(e1);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
/**
* Implementation of PBKDF2 (RFC2898).
*
* @param mac Pre-initialized {@link Mac} instance to use.
* @param S Salt.
* @param c Iteration count.
* @param DK Byte array that derived key will be placed in.
* @param dkLen Intended length, in octets, of the derived key.
*
* @throws GeneralSecurityException
*/
public static void pbkdf2(Mac mac, byte[] S, int c, byte[] DK, int dkLen) throws GeneralSecurityException {
int hLen = mac.getMacLength();
if (dkLen > (Math.pow(2, 32) - 1) * hLen) {
throw new GeneralSecurityException("Requested key length too long");
}
byte[] U = new byte[hLen];
byte[] T = new byte[hLen];
byte[] block1 = new byte[S.length + 4];
int l = (int) Math.ceil((double) dkLen / hLen);
int r = dkLen - (l - 1) * hLen;
arraycopy(S, 0, block1, 0, S.length);
for (int i = 1; i <= l; i++) {
block1[S.length + 0] = (byte) (i >> 24 & 0xff);
block1[S.length + 1] = (byte) (i >> 16 & 0xff);
block1[S.length + 2] = (byte) (i >> 8 & 0xff);
block1[S.length + 3] = (byte) (i >> 0 & 0xff);
mac.update(block1);
mac.doFinal(U, 0);
arraycopy(U, 0, T, 0, hLen);
for (int j = 1; j < c; j++) {
mac.update(U);
mac.doFinal(U, 0);
for (int k = 0; k < hLen; k++) {
T[k] ^= U[k];
}
}
arraycopy(T, 0, DK, (i - 1) * hLen, (i == l ? r : hLen));
}
}
private static byte[] deriveKey(final Mac prf, final byte[] password,
byte[] salt, int iterCount, int keyLengthInBit) {
int keyLength = keyLengthInBit/8;
byte[] key = new byte[keyLength];
try {
int hlen = prf.getMacLength();
int intL = (keyLength + hlen - 1)/hlen; // ceiling
int intR = keyLength - (intL - 1)*hlen; // residue
byte[] ui = new byte[hlen];
byte[] ti = new byte[hlen];
// SecretKeySpec cannot be used, since password can be empty here.
SecretKey macKey = new SecretKey() {
private static final long serialVersionUID = 7874493593505141603L;
@Override
public String getAlgorithm() {
return prf.getAlgorithm();
}
@Override
public String getFormat() {
return "RAW";
}
@Override
public byte[] getEncoded() {
return password;
}
@Override
public int hashCode() {
return Arrays.hashCode(password) * 41 +
prf.getAlgorithm().toLowerCase(Locale.ENGLISH).hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (this.getClass() != obj.getClass()) return false;
SecretKey sk = (SecretKey)obj;
return prf.getAlgorithm().equalsIgnoreCase(
sk.getAlgorithm()) &&
MessageDigest.isEqual(password, sk.getEncoded());
}
};
prf.init(macKey);
byte[] ibytes = new byte[4];
for (int i = 1; i <= intL; i++) {
prf.update(salt);
ibytes[3] = (byte) i;
ibytes[2] = (byte) ((i >> 8) & 0xff);
ibytes[1] = (byte) ((i >> 16) & 0xff);
ibytes[0] = (byte) ((i >> 24) & 0xff);
prf.update(ibytes);
prf.doFinal(ui, 0);
System.arraycopy(ui, 0, ti, 0, ui.length);
for (int j = 2; j <= iterCount; j++) {
prf.update(ui);
prf.doFinal(ui, 0);
// XOR the intermediate Ui's together.
for (int k = 0; k < ui.length; k++) {
ti[k] ^= ui[k];
}
}
if (i == intL) {
System.arraycopy(ti, 0, key, (i-1)*hlen, intR);
} else {
System.arraycopy(ti, 0, key, (i-1)*hlen, hlen);
}
}
} catch (GeneralSecurityException gse) {
throw new RuntimeException("Error deriving PBKDF2 keys");
}
return key;
}
private static byte[] deriveKey(final Mac prf, final byte[] password,
byte[] salt, int iterCount, int keyLengthInBit) {
int keyLength = keyLengthInBit/8;
byte[] key = new byte[keyLength];
try {
int hlen = prf.getMacLength();
int intL = (keyLength + hlen - 1)/hlen; // ceiling
int intR = keyLength - (intL - 1)*hlen; // residue
byte[] ui = new byte[hlen];
byte[] ti = new byte[hlen];
// SecretKeySpec cannot be used, since password can be empty here.
SecretKey macKey = new SecretKey() {
private static final long serialVersionUID = 7874493593505141603L;
@Override
public String getAlgorithm() {
return prf.getAlgorithm();
}
@Override
public String getFormat() {
return "RAW";
}
@Override
public byte[] getEncoded() {
return password;
}
@Override
public int hashCode() {
return Arrays.hashCode(password) * 41 +
prf.getAlgorithm().toLowerCase(Locale.ENGLISH).hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (this.getClass() != obj.getClass()) return false;
SecretKey sk = (SecretKey)obj;
return prf.getAlgorithm().equalsIgnoreCase(
sk.getAlgorithm()) &&
MessageDigest.isEqual(password, sk.getEncoded());
}
};
prf.init(macKey);
byte[] ibytes = new byte[4];
for (int i = 1; i <= intL; i++) {
prf.update(salt);
ibytes[3] = (byte) i;
ibytes[2] = (byte) ((i >> 8) & 0xff);
ibytes[1] = (byte) ((i >> 16) & 0xff);
ibytes[0] = (byte) ((i >> 24) & 0xff);
prf.update(ibytes);
prf.doFinal(ui, 0);
System.arraycopy(ui, 0, ti, 0, ui.length);
for (int j = 2; j <= iterCount; j++) {
prf.update(ui);
prf.doFinal(ui, 0);
// XOR the intermediate Ui's together.
for (int k = 0; k < ui.length; k++) {
ti[k] ^= ui[k];
}
}
if (i == intL) {
System.arraycopy(ti, 0, key, (i-1)*hlen, intR);
} else {
System.arraycopy(ti, 0, key, (i-1)*hlen, hlen);
}
}
} catch (GeneralSecurityException gse) {
throw new RuntimeException("Error deriving PBKDF2 keys");
}
return key;
}
public byte[] derive(byte[] password, byte[] salt, int iterationCount, int dkLen, String provider) throws JoseException
{
Mac prf = MacUtil.getInitializedMac(hmacAlgorithm, new HmacKey(password), provider);
int hLen = prf.getMacLength();
// 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and
// stop.
long maxDerivedKeyLength = 4294967295L; // value of (long) Math.pow(2, 32) - 1;
if (dkLen > maxDerivedKeyLength)
{
throw new UncheckedJoseException("derived key too long " + dkLen);
}
// 2. Let l be the number of hLen-octet blocks in the derived key,
// rounding up, and let r be the number of octets in the last
// block:
//
// l = CEIL (dkLen / hLen) ,
// r = dkLen - (l - 1) * hLen .
//
// Here, CEIL (x) is the "ceiling" function, i.e. the smallest
// integer greater than, or equal to, x.
int l = (int) Math.ceil((double) dkLen / (double) hLen);
int r = dkLen - (l - 1) * hLen;
// 3. For each block of the derived key apply the function F defined
// below to the password P, the salt S, the iteration count c, and
// the block index to compute the block:
//
// T_1 = F (P, S, c, 1) ,
// T_2 = F (P, S, c, 2) ,
// ...
// T_l = F (P, S, c, l) ,
//
// where the function F is defined as the exclusive-or sum of the
// first c iterates of the underlying pseudorandom function PRF
// applied to the password P and the concatenation of the salt S
// and the block index i:
//
// F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
//
// where
//
// U_1 = PRF (P, S || INT (i)) ,
// U_2 = PRF (P, U_1) ,
// ...
// U_c = PRF (P, U_{c-1}) .
//
// Here, INT (i) is a four-octet encoding of the integer i, most
// significant octet first.
// 4. Concatenate the blocks and extract the first dkLen octets to
// produce a derived key DK:
//
// DK = T_1 || T_2 || ... || T_l<0..r-1>
//
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
for (int i = 0; i < l; i++)
{
byte[] block = f(salt, iterationCount, i + 1, prf);
if (i == (l - 1))
{
block = ByteUtil.subArray(block, 0, r);
}
byteArrayOutputStream.write(block, 0, block.length);
}
// 5. Output the derived key DK.
return byteArrayOutputStream.toByteArray();
}
private static byte[] deriveKey(final Mac prf, final byte[] password,
byte[] salt, int iterCount, int keyLengthInBit) {
int keyLength = keyLengthInBit/8;
byte[] key = new byte[keyLength];
try {
int hlen = prf.getMacLength();
int intL = (keyLength + hlen - 1)/hlen; // ceiling
int intR = keyLength - (intL - 1)*hlen; // residue
byte[] ui = new byte[hlen];
byte[] ti = new byte[hlen];
// SecretKeySpec cannot be used, since password can be empty here.
SecretKey macKey = new SecretKey() {
private static final long serialVersionUID = 7874493593505141603L;
@Override
public String getAlgorithm() {
return prf.getAlgorithm();
}
@Override
public String getFormat() {
return "RAW";
}
@Override
public byte[] getEncoded() {
return password;
}
@Override
public int hashCode() {
return Arrays.hashCode(password) * 41 +
prf.getAlgorithm().toLowerCase(Locale.ENGLISH).hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (this.getClass() != obj.getClass()) return false;
SecretKey sk = (SecretKey)obj;
return prf.getAlgorithm().equalsIgnoreCase(
sk.getAlgorithm()) &&
MessageDigest.isEqual(password, sk.getEncoded());
}
};
prf.init(macKey);
byte[] ibytes = new byte[4];
for (int i = 1; i <= intL; i++) {
prf.update(salt);
ibytes[3] = (byte) i;
ibytes[2] = (byte) ((i >> 8) & 0xff);
ibytes[1] = (byte) ((i >> 16) & 0xff);
ibytes[0] = (byte) ((i >> 24) & 0xff);
prf.update(ibytes);
prf.doFinal(ui, 0);
System.arraycopy(ui, 0, ti, 0, ui.length);
for (int j = 2; j <= iterCount; j++) {
prf.update(ui);
prf.doFinal(ui, 0);
// XOR the intermediate Ui's together.
for (int k = 0; k < ui.length; k++) {
ti[k] ^= ui[k];
}
}
if (i == intL) {
System.arraycopy(ti, 0, key, (i-1)*hlen, intR);
} else {
System.arraycopy(ti, 0, key, (i-1)*hlen, hlen);
}
}
} catch (GeneralSecurityException gse) {
throw new RuntimeException("Error deriving PBKDF2 keys");
}
return key;
}
private static byte[] deriveKey(final Mac prf, final byte[] password,
byte[] salt, int iterCount, int keyLengthInBit) {
int keyLength = keyLengthInBit/8;
byte[] key = new byte[keyLength];
try {
int hlen = prf.getMacLength();
int intL = (keyLength + hlen - 1)/hlen; // ceiling
int intR = keyLength - (intL - 1)*hlen; // residue
byte[] ui = new byte[hlen];
byte[] ti = new byte[hlen];
// SecretKeySpec cannot be used, since password can be empty here.
SecretKey macKey = new SecretKey() {
private static final long serialVersionUID = 7874493593505141603L;
@Override
public String getAlgorithm() {
return prf.getAlgorithm();
}
@Override
public String getFormat() {
return "RAW";
}
@Override
public byte[] getEncoded() {
return password;
}
@Override
public int hashCode() {
return Arrays.hashCode(password) * 41 +
prf.getAlgorithm().toLowerCase(Locale.ENGLISH).hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (this.getClass() != obj.getClass()) return false;
SecretKey sk = (SecretKey)obj;
return prf.getAlgorithm().equalsIgnoreCase(
sk.getAlgorithm()) &&
MessageDigest.isEqual(password, sk.getEncoded());
}
};
prf.init(macKey);
byte[] ibytes = new byte[4];
for (int i = 1; i <= intL; i++) {
prf.update(salt);
ibytes[3] = (byte) i;
ibytes[2] = (byte) ((i >> 8) & 0xff);
ibytes[1] = (byte) ((i >> 16) & 0xff);
ibytes[0] = (byte) ((i >> 24) & 0xff);
prf.update(ibytes);
prf.doFinal(ui, 0);
System.arraycopy(ui, 0, ti, 0, ui.length);
for (int j = 2; j <= iterCount; j++) {
prf.update(ui);
prf.doFinal(ui, 0);
// XOR the intermediate Ui's together.
for (int k = 0; k < ui.length; k++) {
ti[k] ^= ui[k];
}
}
if (i == intL) {
System.arraycopy(ti, 0, key, (i-1)*hlen, intR);
} else {
System.arraycopy(ti, 0, key, (i-1)*hlen, hlen);
}
}
} catch (GeneralSecurityException gse) {
throw new RuntimeException("Error deriving PBKDF2 keys");
}
return key;
}
private static byte[] deriveKey(final Mac prf, final byte[] password,
byte[] salt, int iterCount, int keyLengthInBit) {
int keyLength = keyLengthInBit/8;
byte[] key = new byte[keyLength];
try {
int hlen = prf.getMacLength();
int intL = (keyLength + hlen - 1)/hlen; // ceiling
int intR = keyLength - (intL - 1)*hlen; // residue
byte[] ui = new byte[hlen];
byte[] ti = new byte[hlen];
// SecretKeySpec cannot be used, since password can be empty here.
SecretKey macKey = new SecretKey() {
@java.io.Serial
private static final long serialVersionUID = 7874493593505141603L;
@Override
public String getAlgorithm() {
return prf.getAlgorithm();
}
@Override
public String getFormat() {
return "RAW";
}
@Override
public byte[] getEncoded() {
return password;
}
@Override
public int hashCode() {
return Arrays.hashCode(password) * 41 +
prf.getAlgorithm().toLowerCase(Locale.ENGLISH).hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (this.getClass() != obj.getClass()) return false;
SecretKey sk = (SecretKey)obj;
return prf.getAlgorithm().equalsIgnoreCase(
sk.getAlgorithm()) &&
MessageDigest.isEqual(password, sk.getEncoded());
}
};
prf.init(macKey);
byte[] ibytes = new byte[4];
for (int i = 1; i <= intL; i++) {
prf.update(salt);
ibytes[3] = (byte) i;
ibytes[2] = (byte) ((i >> 8) & 0xff);
ibytes[1] = (byte) ((i >> 16) & 0xff);
ibytes[0] = (byte) ((i >> 24) & 0xff);
prf.update(ibytes);
prf.doFinal(ui, 0);
System.arraycopy(ui, 0, ti, 0, ui.length);
for (int j = 2; j <= iterCount; j++) {
prf.update(ui);
prf.doFinal(ui, 0);
// XOR the intermediate Ui's together.
for (int k = 0; k < ui.length; k++) {
ti[k] ^= ui[k];
}
}
if (i == intL) {
System.arraycopy(ti, 0, key, (i-1)*hlen, intR);
} else {
System.arraycopy(ti, 0, key, (i-1)*hlen, hlen);
}
}
} catch (GeneralSecurityException gse) {
throw new RuntimeException("Error deriving PBKDF2 keys", gse);
}
return key;
}