package im.actor.crypto.primitives.hmac;
import im.actor.crypto.primitives.util.ByteStrings;
import im.actor.crypto.primitives.Digest;
import static im.actor.crypto.primitives.util.ByteStrings.merge;
import static im.actor.crypto.primitives.util.ByteStrings.substring;
public class HMAC implements Digest {
private Digest digest;
private final byte[] secret;
private final byte[] outerKeyPad;
private final byte[] innerKeyPad;
public HMAC(byte[] secret, Digest digest) {
this.digest = digest;
byte[] fixedSecret = new byte[digest.getDigestSize()];
if (secret.length > digest.getDigestSize()) {
digest.reset();
digest.update(secret, 0, secret.length);
digest.doFinal(fixedSecret, 0);
} else if (secret.length < digest.getDigestSize()) {
ByteStrings.write(fixedSecret, 0, secret, 0, secret.length);
for (int i = secret.length; i < fixedSecret.length; i++) {
fixedSecret[i] = 0;
}
} else {
fixedSecret = secret;
}
this.secret = fixedSecret;
outerKeyPad = new byte[digest.getDigestSize()];
innerKeyPad = new byte[digest.getDigestSize()];
for (int i = 0; i < outerKeyPad.length; i++) {
outerKeyPad[i] = (byte) (0x5c ^ (this.secret[i] & 0xFF));
innerKeyPad[i] = (byte) (0x36 ^ (this.secret[i] & 0xFF));
}
}
@Override
public void reset() {
digest.reset();
digest.update(innerKeyPad, 0, innerKeyPad.length);
}
@Override
public void update(byte[] src, int offset, int length) {
digest.update(src, offset, length);
}
@Override
public void doFinal(byte[] dest, int destOffset) {
byte[] innnerHash = new byte[digest.getDigestSize()];
digest.doFinal(innnerHash, 0);
digest.reset();
digest.update(outerKeyPad, 0, outerKeyPad.length);
digest.update(innnerHash, 0, innnerHash.length);
digest.doFinal(dest, destOffset);
reset();
}
@Override
public int getDigestSize() {
return digest.getDigestSize();
}
}