package com.oracle.security.ucrypto;
import java.lang.ref.*;
import java.io.ByteArrayOutputStream;
import java.util.*;
import java.util.concurrent.ConcurrentSkipListSet;
import java.security.*;
public abstract class NativeDigestMD extends MessageDigestSpi
implements Cloneable {
private static final int MECH_MD5 = 1;
private static final int MECH_SHA1 = 2;
private static final int MECH_SHA256 = 3;
private static final int MECH_SHA224 = 4;
private static final int MECH_SHA384 = 5;
private static final int MECH_SHA512 = 6;
private final int digestLen;
private final int mech;
private DigestContextRef pCtxt = null;
private static class DigestContextRef extends PhantomReference<NativeDigestMD>
implements Comparable<DigestContextRef> {
private static ReferenceQueue<NativeDigestMD> refQueue =
new ReferenceQueue<NativeDigestMD>();
private static Set<DigestContextRef> refList =
new ConcurrentSkipListSet<DigestContextRef>();
private final long id;
private final int mech;
private static void drainRefQueueBounded() {
while (true) {
DigestContextRef next = (DigestContextRef) refQueue.poll();
if (next == null) break;
next.dispose(true);
}
}
DigestContextRef(NativeDigestMD nc, long id, int mech) {
super(nc, refQueue);
this.id = id;
this.mech = mech;
refList.add(this);
UcryptoProvider.debug("Resource: track Digest Ctxt " + this.id);
drainRefQueueBounded();
}
public int compareTo(DigestContextRef other) {
if (this.id == other.id) {
return 0;
} else {
return (this.id < other.id) ? -1 : 1;
}
}
void dispose(boolean needFree) {
refList.remove(this);
try {
if (needFree) {
UcryptoProvider.debug("Resource: free Digest Ctxt " + this.id);
NativeDigestMD.nativeFree(mech, id);
} else UcryptoProvider.debug("Resource: stop tracking Digest Ctxt " + this.id);
} finally {
this.clear();
}
}
}
NativeDigestMD(int mech, int digestLen) {
this.digestLen = digestLen;
this.mech = mech;
}
protected int engineGetDigestLength() {
return digestLen;
}
protected synchronized void engineReset() {
if (pCtxt != null) {
pCtxt.dispose(true);
pCtxt = null;
}
}
protected synchronized byte[] engineDigest() {
byte[] digest = new byte[digestLen];
try {
int len = engineDigest(digest, 0, digestLen);
if (len != digestLen) {
throw new UcryptoException("Digest length mismatch." +
" Len: " + len + ". digestLen: " + digestLen);
}
return digest;
} catch (DigestException de) {
throw new UcryptoException("Internal error", de);
}
}
protected synchronized int engineDigest(byte[] out, int ofs, int len)
throws DigestException {
if (len < digestLen) {
throw new DigestException("Output buffer must be at least " +
digestLen + " bytes long. Got: " + len);
}
if ((ofs < 0) || (len < 0) || (ofs > out.length - len)) {
throw new DigestException("Buffer too short to store digest. " +
"ofs: " + ofs + ". len: " + len + ". out.length: " + out.length);
}
if (pCtxt == null) {
pCtxt = new DigestContextRef(this, nativeInit(mech), mech);
}
try {
int status = nativeDigest(mech, pCtxt.id, out, ofs, digestLen);
if (status != 0) {
throw new DigestException("Internal error: " + status);
}
} finally {
pCtxt.dispose(false);
pCtxt = null;
}
return digestLen;
}
protected synchronized void engineUpdate(byte in) {
byte[] temp = { in };
engineUpdate(temp, 0, 1);
}
protected synchronized void engineUpdate(byte[] in, int ofs, int len) {
if (len == 0) {
return;
}
if ((ofs < 0) || (len < 0) || (ofs > in.length - len)) {
throw new ArrayIndexOutOfBoundsException("ofs: " + ofs + ". len: "
+ len + ". in.length: " + in.length);
}
if (pCtxt == null) {
pCtxt = new DigestContextRef(this, nativeInit(mech), mech);
}
nativeUpdate(mech, pCtxt.id, in, ofs, len);
}
public synchronized Object clone() throws CloneNotSupportedException {
NativeDigestMD copy = (NativeDigestMD) super.clone();
if (pCtxt != null) {
copy.pCtxt = new DigestContextRef(this, nativeClone(mech, pCtxt.id), mech);
}
return copy;
}
protected static final native long nativeInit(int mech);
protected static final native int nativeUpdate(int mech, long pCtxt, byte[] in, int ofs, int inLen);
protected static final native int nativeDigest(int mech, long pCtxt, byte[] out, int ofs, int digestLen);
protected static final native long nativeClone(int mech, long pCtxt);
private static final native void nativeFree(int mech, long id);
public static final class MD5 extends NativeDigestMD {
public MD5() {
super(MECH_MD5, 16);
}
}
public static final class SHA1 extends NativeDigestMD {
public SHA1() {
super(MECH_SHA1, 20);
}
}
public static final class SHA256 extends NativeDigestMD {
public SHA256() {
super(MECH_SHA256, 32);
}
}
public static final class SHA384 extends NativeDigestMD {
public SHA384() {
super(MECH_SHA384, 48);
}
}
public static final class SHA512 extends NativeDigestMD {
public SHA512() {
super(MECH_SHA512, 64);
}
}
}