DHPublicKey与byte[]转换的问题

背景:

网络上经常采用Diffie-Hellman算法来交换密钥。通讯的双方首先共享2个公开数字:p和g。其中p是一个大质数,g通常等于2。则\( Z_p=\{a=g^n \pmod{p}, n \in N \} \) 构成一个整数群。

密钥的生成方法:

\(Z_p\)中选取一个随机数x,然后计算\( y=g^x \)。那么x,y构成一个keypair。x是私钥,y是公钥。

那么每个人只需要把自己的公钥发出去,然后通信的时候选取一个对称加密算法,利用\(y^x\)作为通信的加密密钥即可。其中x是自己的私钥,y是对方的公钥。

实际在用JAVA实现的时候:

公钥和私钥可以通过java.security.KeyPairGenerator生成。

//DH是算法名,SunJCE是Java Security API的Provider名,此处使用JDK自带的的SunJCE。
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH","SunJCE");

然后初始化KeyPairGenerator 这时需要传入一个java.security.spec.AlgorithmParameterSpec对象。

kpg.initialize(MODP_GROUP2);

MODP_GROUP2对象是这么来的:

StringBuffer sb = new StringBuffer();
sb.append("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1");
sb.append("29024E088A67CC74020BBEA63B139B22514A08798E3404DD");
sb.append("EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245");
sb.append("E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED");
sb.append("EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381");
sb.append("FFFFFFFFFFFFFFFF");

BigInteger prime = new BigInteger(sb.toString(), 16);
BigInteger generator = BigInteger.valueOf(2);

MODP_GROUP2 = new DHParameterSpec(prime, generator);

它描述了DH算法所需要用到的p和g等于几。我在这里所用的prime来自于rfc2412的OAKLEY Key Group 2。

有了上述信息,就可以开始生成keypair:

KeyPair aliceDHKeyPair = kpg.generateKeyPair();
DHPublicKey dp = (DHPublicKey) aliceDHKeyPair.getPublic();

下面的问题是,怎么把DHPublicKey发出去?

首先DHPublicKey自带有一个getEncoded()方法,默认是采用X.509方式编码。但是这种编码方式,会把p,g,y都写入进入byte[]中。这对于实际应用来说,根本不必要啊,我只需要公钥(y)就行了啊!

于是我就把Y拿出来,然后转byte[]。

final int length=dp.getY().bitLength();
byte[] ret = dp.getY().toByteArray();        
if(length==1024)
     ret=Arrays.copyOfRange(ret, 1, ret.length);

这其中多了一层Array.copyOfRange是因为,BigInteger的toByteArray()方法,会把符号位也写入最终结果中。那么,如果Y恰好是1024位的,最终就会得到一个129字节的byte[](其中第一个字节是0)

可是当我把这个byte[]收到时候再转成PubicKey,发现跟发送前不一样了:

KeyFactory keyFactory = KeyFactory.getInstance("DH", PROVIDER);
BigInteger y = new BigInteger(1, ret);
DHPublicKeySpec spec = new DHPublicKeySpec(y, MODP_GROUP2.getP(),
                MODP_GROUP2.getG());
DHPublicKey dp2 = (DHPublicKey) keyFactory.generatePublic(spec);

Assert.assertEquals(dp, dp2); //Always Fail

这个fail的原因在于,尽管p、g、Y都相等,但是l不相等。非常令我崩溃。发送前,DHPublicKey 的l=512,发送后用keyFactory得到的DHPublicKey 的l=0。JDK文档中对l的解释是“the size in bits of the random exponent (private value)”。但是我不知道为什么即使我在DHParameterSpec将它设置成512,得到的Y依然是1024字节。我在想这个要不要紧,要么忍了吧。改改test case。

此博客中的热门博文

在windows下使用llvm+clang

少写代码,多读别人写的代码

tensorflow distributed runtime初窥