最近在寫(xiě)一個(gè)Java的消息服務(wù)器,同時(shí)需要做一個(gè).NET版本的客戶端。他們之間需要安全通訊,基于一些簡(jiǎn)單的密碼協(xié)議,用到公鑰加密、對(duì)稱加密、Hash算法。這個(gè)過(guò)程中,我對(duì)這兩個(gè)平臺(tái)的加密部分有了一定了解,以下也是我的一些新的認(rèn)識(shí)吧。
1、對(duì)稱加密
1) Java 1.5的對(duì)稱加密很簡(jiǎn)單,提供的算法也較多??梢哉f(shuō)是,使用簡(jiǎn)單,傻瓜式,而且功能齊全。
例如:
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decryptText = cipher.doFinal(data);
2) .NET 2.0的對(duì)稱加密,缺省加密模式是CBC,CBC加密的時(shí)候,需要一個(gè)密鑰的同時(shí),還需要初始化向量IV,這會(huì)使得初學(xué)入者使用起來(lái)不方便,這個(gè)問(wèn)題到是十分容易對(duì)付的,修改一下配置就好了。
SymmetricAlgorithm algorithm = SymmetricAlgorithm.Create(algorithmName);
algorithm.Mode = CipherMode.ECB;
algorithm.Key = key;
algorithm.Padding = PaddingMode.PKCS7;
通過(guò)這種設(shè)置之后,就能夠跟Java通訊操作,互為加密解密。
3) .NET 2.0和Java 1.5方面,加密算法的名字有些地方稍有差別。
AES <==> Rijndael
DESede <==> TripleDES
這是似乎是常識(shí)。
2、公鑰加密算法RSA
1) Java 1.5中,RSAPublicKey進(jìn)行g(shù)etEncoded()得到字節(jié)數(shù)組是ASN.1編碼的。逆轉(zhuǎn)回來(lái)需要使用X509EncodedKeySpec,這個(gè)細(xì)節(jié)需要閱讀文檔細(xì)節(jié)或者對(duì)密碼學(xué)有一定了解才知道。例如:
//public key ==> bytes
PublicKey publicKey = 
byte[] rawPublicKey = publicKey.getEncoded();
// bytes ==> public key
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(rawPublicKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
Key newPublicKey = keyFactory.generatePublic(x509KeySpec);
除此之外,Java的公鑰加密部分,還是相當(dāng)易于使用的。風(fēng)格依然是功能簡(jiǎn)單,傻瓜式使用,功能齊全。
Java中,支持ASN.1編碼,但是隱藏其中,使用者完全覺(jué)察不到。
2) .NET 2.0中,設(shè)計(jì)有些混亂,并不支持ASN.1編碼。但是Mono似乎在做ASN.1編碼的支持。為此我自己借鑒一個(gè)Java開(kāi)元JCE的實(shí)現(xiàn),實(shí)現(xiàn)了一個(gè).NET版本的ASN Parser和ASN Builder,花了兩天時(shí)間。如下:
public static RSAParameters ASN1ToPublicKey(byte[] rawPublicKey)
{
ASN1InputStream asnInput = new ASN1InputStream(rawPublicKey);
ASN1Sequence asnSeq = (ASN1Sequence)asnInput.ReadObject();
SubjectPublicKeyInfo subjectPublicKeyInfo = new SubjectPublicKeyInfo(asnSeq);
DERObjectIdentifier algOid = subjectPublicKeyInfo.AlgorithmId.ObjectId;
RSAPublicKeyStructure pubKey = new RSAPublicKeyStructure(
(ASN1Sequence)subjectPublicKeyInfo.PublicKey);
byte[] modulus = pubKey.Modulus;
byte[] publicExponent = pubKey.PublicExponent;
RSAParameters pram = new RSAParameters();
pram.Modulus = modulus;
pram.Exponent = publicExponent;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(pram);
return pram;
}
public static byte[] PublicKeyToASN1(RSAParameters pram)
{
SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption,
new DERNull()), new RSAPublicKeyStructure(pram.Modulus, pram.Exponent).DERObject);
byte[] rawPublicKey = info.GetDEREncoded();
return rawPublicKey;
}
3、總體感覺(jué)
1) Java的安全模塊設(shè)計(jì)得還是很好的,簡(jiǎn)單易用,功能也齊全。
2) .NET 2.0則是有點(diǎn)亂,命名風(fēng)格和系統(tǒng)框架有些不協(xié)調(diào),功能欠缺,代碼組織的不夠理想。
3) 在Mono中,對(duì)安全的支持要比微軟已發(fā)布的要好,從網(wǎng)上可以看到,.NET Framework 2.0的一些特性也是從Mono中借鑒過(guò)來(lái)的。
4) 甚至可以認(rèn)為,.NET加密模塊的開(kāi)發(fā)團(tuán)隊(duì)能力可能不是很強(qiáng)。就如那一句話“編寫(xiě)糟糕的代碼并非我們的專利”。