|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.provider; |
|
|
|
import javax.crypto.Mac; |
|
import javax.crypto.spec.SecretKeySpec; |
|
import java.security.InvalidKeyException; |
|
import java.security.NoSuchAlgorithmException; |
|
import java.security.NoSuchProviderException; |
|
import java.security.SecureRandomParameters; |
|
import java.util.Arrays; |
|
import java.util.Collections; |
|
import java.util.HexFormat; |
|
import java.util.List; |
|
|
|
public class HmacDrbg extends AbstractHashDrbg { |
|
|
|
private Mac mac; |
|
|
|
private String macAlg; |
|
|
|
private byte[] v; |
|
private byte[] k; |
|
|
|
public HmacDrbg(SecureRandomParameters params) { |
|
mechName = "HMAC_DRBG"; |
|
configure(params); |
|
} |
|
|
|
private void status() { |
|
if (debug != null) { |
|
debug.println(this, "V = " + HexFormat.of().formatHex(v)); |
|
debug.println(this, "Key = " + HexFormat.of().formatHex(k)); |
|
debug.println(this, "reseed counter = " + reseedCounter); |
|
} |
|
} |
|
|
|
|
|
private void update(List<byte[]> inputs) { |
|
try { |
|
|
|
mac.init(new SecretKeySpec(k, macAlg)); |
|
mac.update(v); |
|
mac.update((byte) 0); |
|
for (byte[] input: inputs) { |
|
mac.update(input); |
|
} |
|
k = mac.doFinal(); |
|
|
|
|
|
mac.init(new SecretKeySpec(k, macAlg)); |
|
v = mac.doFinal(v); |
|
|
|
if (!inputs.isEmpty()) { |
|
|
|
mac.update(v); |
|
mac.update((byte) 1); |
|
for (byte[] input: inputs) { |
|
mac.update(input); |
|
} |
|
k = mac.doFinal(); |
|
|
|
|
|
mac.init(new SecretKeySpec(k, macAlg)); |
|
v = mac.doFinal(v); |
|
} // else Step 3 |
|
|
|
// Step 6. Return |
|
} catch (InvalidKeyException e) { |
|
throw new InternalError(e); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
protected void initEngine() { |
|
macAlg = "HmacSHA" + algorithm.substring(4); |
|
try { |
|
|
|
|
|
|
|
*/ |
|
mac = Mac.getInstance(macAlg, "SunJCE"); |
|
} catch (NoSuchProviderException | NoSuchAlgorithmException e) { |
|
|
|
try { |
|
mac = Mac.getInstance(macAlg); |
|
} catch (NoSuchAlgorithmException exc) { |
|
throw new InternalError( |
|
"internal error: " + macAlg + " not available.", exc); |
|
} |
|
} |
|
} |
|
|
|
|
|
@Override |
|
protected final synchronized void hashReseedInternal(List<byte[]> input) { |
|
|
|
// 800-90Ar1 10.1.2.3: Instantiate Process. |
|
|
|
if (v == null) { |
|
k = new byte[outLen]; |
|
v = new byte[outLen]; |
|
Arrays.fill(v, (byte) 1); |
|
} |
|
|
|
|
|
update(input); |
|
|
|
|
|
reseedCounter = 1; |
|
//status(); |
|
|
|
// Step 4: Return |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public synchronized void generateAlgorithm( |
|
byte[] result, byte[] additionalInput) { |
|
|
|
if (debug != null) { |
|
debug.println(this, "generateAlgorithm"); |
|
} |
|
|
|
// 800-90Ar1 10.1.2.5: HMAC_DRBG_Generate Process |
|
|
|
// Step 1: Check reseed_counter. Will not fail. Already checked in |
|
// AbstractDrbg#engineNextBytes. |
|
|
|
|
|
if (additionalInput != null) { |
|
update(Collections.singletonList(additionalInput)); |
|
} |
|
|
|
|
|
int pos = 0; |
|
int len = result.length; |
|
|
|
|
|
while (len > 0) { |
|
|
|
try { |
|
mac.init(new SecretKeySpec(k, macAlg)); |
|
} catch (InvalidKeyException e) { |
|
throw new InternalError(e); |
|
} |
|
v = mac.doFinal(v); |
|
|
|
System.arraycopy(v, 0, result, pos, |
|
len > outLen ? outLen : len); |
|
|
|
len -= outLen; |
|
if (len <= 0) { |
|
|
|
break; |
|
} |
|
pos += outLen; |
|
} |
|
|
|
// Step 5: No need to truncate |
|
|
|
|
|
if (additionalInput != null) { |
|
update(Collections.singletonList(additionalInput)); |
|
} else { |
|
update(Collections.emptyList()); |
|
} |
|
|
|
|
|
reseedCounter++; |
|
|
|
//status(); |
|
|
|
// Step 8. Return |
|
} |
|
} |