所以我不确定我是否正确地这样做了。我在这里使用伪代码:http://en.wikipedia.org/wiki/MD5
它说:
//Pre-processing:
append "1" bit to message
append "0" bits until message length in bits ≡ 448 (mod 512)
append length to message
在java中,我能否将消息转换为字节数组。然后通过获取字符串长度* 8来获取位数。然后执行类似448 - ((#bits+1) mod 512)
的操作以获取要追加的0位数。
然后将该字节数组复制到另一个数组,但用0填充第一个字节,然后填充1。
示例:
字符串是746位
然后我会做448 - ((746+1) mod 512) = 213
所以我需要用213“0”位然后1“1”位填充字符串。
那么我的数组就像是
byteArr[0] = 0x00
byteArr[1] = 0x00
...
byteArr[27] = 000001(Rest of message bits)
byteArr[n] = Rest of the bytes from message
我怎样才能找到1的位置?基本上,如果我追加1位,我怎么能知道它是否会产生短路。
是否有更简单的方法或其他方式来做到这一点?
答案 0 :(得分:2)
这些位必须附加到消息的 end ,而不是开头。在将消息填充到448位mod 512之后,您必须附加消息的长度(没有填充位)。 但只要这不是练习,你应该使用JB Nizet提到的算法。
答案 1 :(得分:2)
当其他人抓到时,“附加”意味着添加到最后。所以你真正希望得到的是一个0x80的字节,在消息之后是一堆0字节,直到总字节数为8,小于64的倍数。
答案 2 :(得分:0)
有一种更简单的方法:只需使用Java SE API为您提供MD5 algorithm already implemented。
旁注:Java中的String包含字符,而不是字节。不要使用术语“字符串”来表示二进制消息。使用术语字节数组。
答案 3 :(得分:0)
如果你实施加密算法,你应该把它作为一个好习惯,将官方规范作为实现的蓝图。和维基百科一样,我仍然不会依赖它来实现安全关键算法。当然,除了官方规范之外,还可以使用它。所以我从RFC 1321开始,只会从其他来源获得“灵感”。
RFC 1321甚至包含C中的实现,你也可以检查它。关于填充步骤,他们说3.1步骤1.附加填充位
消息被“填充”(扩展),以便其长度(以位为单位) 全等到448,模512.也就是说,消息是扩展的 它只是64位,是512位长的倍数。 即使消息的长度为,也始终执行填充 已经与448一致,模512。
填充如下执行:将单个“1”位附加到 消息,然后附加“0”位,以便以位为单位的长度 填充的消息变为全等448,模512.总之,在 附加至少一位且最多512位。
这意味着你必须首先附加1,然后用剩余的零填充,而不是反过来。填充的其余位(包括“1”)将始终是8的倍数,因为您的输入是字节,其位长也是8的倍数。因此,假设您必须填充128位。这意味着1加127 0位。总共,这是16(16 * 8 = 128)字节的填充,其中第一个字节的最高位设置为1,即第一个字节将变为0x80,其余为0x00。所以这意味着您可以将此填充步骤简化为
答案 4 :(得分:-2)
你所说的是腌制哈希。
我就是这样做的。
public static byte[] getSecure8ByteSalt(){
SecureRandom random = null;
try {
random = SecureRandom.getInstance("SHA1PRNG");
byte [] bSalt = new byte[8];
random.nextBytes(bSalt);
return bSalt;
} catch (NoSuchAlgorithmException e) {
log.error(e.getMessage(),e);
}
return new byte[]{
(byte)0xA9, (byte)0x9B, (byte)0xC8, (byte)0x32,
(byte)0x56, (byte)0x34, (byte)0xE3, (byte)0x03
};
}
调用salt的方法称为hash:
private void hash(String passwd, int hashType){
byte[] bSalt = new byte[8];
try {
if(this.salt == null){
bSalt = getSecure8ByteSalt();
}
else{
bSalt = base64ToByte(salt);
}
} catch (IOException e1) {
log.error(e1.getMessage(),e1);
return;
}
byte[] bDigest=null;
try {
bDigest = getHash(ITERATION_NUMBER,passwd,bSalt,hashType);
} catch (NoSuchAlgorithmException e) {
log.error(e.getMessage(),e);
}
String sDigest = byteToBase64(bDigest);
if(this.salt == null)
setSalt(byteToBase64(bSalt));
setPasswordHash(sDigest);
}
Byte to base 64方法:
public static byte[] base64ToByte(String data) throws IOException {
BASE64Decoder decoder = new BASE64Decoder();
return decoder.decodeBuffer(data);
}
public static String byteToBase64(byte[] data){
BASE64Encoder endecoder = new BASE64Encoder();
return endecoder.encode(data);
}
getHash方法:
private byte[] getHash(int iterationNb, String password, byte[] salt, int hashType) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance(HASH_TYPE[hashType]);
digest.reset();
digest.update(salt);
byte[] input = null;
try {
input = digest.digest(password.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
log.error(e.getMessage(),e);
}
for (int i = 0; i < iterationNb; i++) {
digest.reset();
input = digest.digest(input);
}
return input;
}