SOURCECODE
package net.i2p.crypto;
import java.security.DigestException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.LinkedBlockingQueue;
import net.i2p.I2PAppContext;
import net.i2p.data.Hash;
/**
* Defines a wrapper for SHA-256 operation.
*
* As of release 0.8.7, uses java.security.MessageDigest by default.
* As of release 0.9.25, uses only MessageDigest.
* GNU-Crypto gnu.crypto.hash.Sha256Standalone
* is removed as of 0.9.28.
*/
public final class SHA256Generator {
private final LinkedBlockingQueue<MessageDigest> _digests;
/**
* @param context unused
*/
public SHA256Generator(I2PAppContext context) {
_digests = new LinkedBlockingQueue<MessageDigest>(32);
}
public static final SHA256Generator getInstance() {
return I2PAppContext.getGlobalContext().sha();
}
/**
* Calculate the SHA-256 hash of the source and cache the result.
* @param source what to hash
* @return hash of the source
*/
public final Hash calculateHash(byte[] source) {
return calculateHash(source, 0, source.length);
}
/**
* Calculate the hash and cache the result.
* @param source what to hash
*/
public final Hash calculateHash(byte[] source, int start, int len) {
MessageDigest digest = acquire();
digest.update(source, start, len);
byte rv[] = digest.digest();
release(digest);
return Hash.create(rv);
}
/**
* Use this if you only need the data, not a Hash object.
* Does not cache.
* @param out needs 32 bytes starting at outOffset
*/
public final void calculateHash(byte[] source, int start, int len, byte out[], int outOffset) {
MessageDigest digest = acquire();
digest.update(source, start, len);
try {
digest.digest(out, outOffset, Hash.HASH_LENGTH);
} catch (DigestException e) {
throw new RuntimeException(e);
} finally {
release(digest);
}
}
private MessageDigest acquire() {
MessageDigest rv = _digests.poll();
if (rv != null)
rv.reset();
else
rv = getDigestInstance();
return rv;
}
private void release(MessageDigest digest) {
_digests.offer(digest);
}
/**
* Return a new MessageDigest from the system libs.
* @since 0.8.7, public since 0.8.8 for FortunaStandalone
*/
public static MessageDigest getDigestInstance() {
try {
return MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
详细笔记
首先这是一个final类,说明该类SHA256Generator是不可以被继承,并且该类的所有成员变量和成员函数都是final修饰的
成员变量
_digests 是prvate类型,是LinkedBlockingQueue类的,这个是可变大小的阻塞队列,first in first out,最早在队列中元素是在队伍的最前边。
LinkedBlockingQueue
的泛型限定是MessageDigest类,这个MessageDigest类为应用程序提供了消息摘要算法的功能,如SHA-1或SHA-256。消息摘要是安全的单向哈希函数,它接受任意大小的数据并输出固定长度的哈希值。
成员函数
- SHA256Generator 构造函数: new 一个32大小的
LinkedBlockingQueue<MessageDigest>
- getInstance() 从i2paoocontext’.getglobalcontext获取sha,这个具体是怎么用的之后再看
public static final SHA256Generator getInstance() {
return I2PAppContext.getGlobalContext().sha();
}
- 三个重载函数:calculateHash,从名字我们就可以看出这是在计算hash值的函数。具体分析i下代码
public final Hash calculateHash(byte[] source) {
return calculateHash(source, 0, source.length);
}
/**
* Calculate the hash and cache the result.
* @param source what to hash
*/
public final Hash calculateHash(byte[] source, int start, int len) {
MessageDigest digest = acquire();
digest.update(source, start, len);
byte rv[] = digest.digest();
release(digest);
return Hash.create(rv);
}
/**
* Use this if you only need the data, not a Hash object.
* Does not cache.
* @param out needs 32 bytes starting at outOffset
*/
public final void calculateHash(byte[] source, int start, int len, byte out[], int outOffset) {
MessageDigest digest = acquire();
digest.update(source, start, len);
try {
digest.digest(out, outOffset, Hash.HASH_LENGTH);
} catch (DigestException e) {
throw new RuntimeException(e);
} finally {
release(digest);
}
}
前两个函数我们可以理解,分别是指定位置和长度的以及未指定位置和长度的计算hash的函数,如果未指定则默认0和整个byte数组都进行hash计算
该函数返回一个hash对象,hash类在另外一个文章中有解析
我们先看该函数,首先创建一个MessageDigest 的对象digest,该digest使用acquire来初始化。
看一下acquire函数
private MessageDigest acquire() {
MessageDigest rv = _digests.poll();
if (rv != null)
rv.reset();
else
rv = getDigestInstance();
return rv;
}
/**
* Return a new MessageDigest from the system libs.
* @since 0.8.7, public since 0.8.8 for FortunaStandalone
*/
public static MessageDigest getDigestInstance() {
try {
return MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
acquire函数是创建一个messagedigest类的对象rv,首先是rv = _digests.poll,因为我不喜欢用队列,所以对poll这个记成了pull,就没想到,又因为我想digests是messagedigets,(其实是我记错了,其实是messagedigest队列),所以在messagedigets类中找了半天没发现poll函数,其实本身是队列的函数。其实我们整体来看也可以见着端倪,这anquir函数明显是用来初始化的一个函数,应该不会有其他操作。
后来意识到我错误,把_digets本身一个队列当成了他的元素messagedigest种类了,直接去linkedblockingqueue类去查函数,poll是返回队列头部的元素,如果是空队列,那么返回null
所以rv如果是null的,那么说明队伍是空的,调用getDigestInstance函数,参数为空,这里要注意的是这里调用的不是messageDigest的getDigestInstance的函数,而是自己写了一个,同样在代码中,返回一个sha256的messagedigest的对象。
以上就是acquire函数的功能,综合来讲,acquire函数就是被calculatehash函数调用,用来进行初始化messagedigest类的对象的独立出来的一个函数。
**继续来看cacluatehash函数。digest初始化之后,调用了update函数,这个函数与变量名字同名,我们查询api看一下,update函数的描述是
Updates the digest using the specified array of bytes, starting at the specified offset.
就是根据给定的数据来更新digest,意思是根据给定的byte来开始计算hash。
然后调用了digest函数
Completes the hash computation by performing final operations such as padding. The digest is reset after this call is made.
Returns:
无参数的digets函数是意思是,完成hash计算的最后步骤,例如填充等步骤,并且reset digest这个对象。他的返回值是字节数组,我们把它保存到了rv上,
然后release,根据返回的字节数组,调用hash类的create函数,这里的hash类到底是怎么做的在这里不需要关注,可以根据命名以及作用来分析可能是自己定义的用来存储hash值的一个类,其中有关于该sha-256值的相关的信息
而最后一个calculateHash这个比较特殊,第一是他没有返回值,第二是他的digest函数的参数不一样。
首先是没有返回值的事情,没有返回值说明不需要返回一个hash对象,但是因为本事是计算hash的,所以hash值肯定存储在了另外的地方,,所以在参数中有一个byte out[],为什么这样将这个字节数组放在参数列表中,因为这个函数不一定被用到,在用到的时候再创建,尽量的节省空间。至于digest的其他参数
buf - output buffer for the computed digest
offset - offset into the output buffer to begin storing the digest
len - number of bytes within buf allotted for the digest
至于release函数,是将digest对象放到_digest的队列中去,但是这个时候digest应该已经reset了,因为messagedigest每次调用这个digest函数之后都会reset,digest