http://blog.csdn.net/raorq/archive/2010/03/29/5427260.aspx
1
、前言
隨著移動商業的不斷髮展,對於移動使用者和
無線
應用
程式開發
人員而言,
安全
性正在成為一個重要方
面。
無線通訊是無線電波攔截容易擷取的目標,而無線裝置幾乎沒有任何計算能力來支援所有通訊資料的強加密。
而
目前
開發得很好的點對點安全性技術(如
SSL/TLS
和
HTTPS
)
並
不
適合於多供應商、多中間
Web
服務
的
網
絡拓撲圖
。因此
重點
必須
集中在保護內容本身
而不是傳遞內容的串連上。
本文將討論使用一種常見的安全性技術:數位簽章。數位簽章可以滿足網路通訊安全的四方面標
准:
可認證性:通訊雙方必須標識其本身。密鑰憑證上的數位簽章可以驗證該公開金鑰的可靠性以及持有它
的那一方的可靠性。
資料完整性:通訊雙方必須確保內容在傳送期間不被改變。數位簽章是保證資料完整性的最常用技
術。
資料機密性:有時候,通訊資料是敏感的,必須保密。數位簽章不提供資料機密性。我們必須使用
資料加密。
不可抵賴性:訊息發送之後,發送方隨後應該不能否認它。數位簽章提供了部分解決方案。如果以
數字方式對訊息進行簽名,則發送方無法否認其責任,因為只有他能提供這種簽名。
2
、
j2me
安全機制簡介
J2ME
平台是由配置(
Configuration
)
和簡表(
Profile
)構成的。配置是提供給最大範圍裝置使用的最小類庫集合,在配置中同時包含
Java
虛
擬機。簡表是針對一系列裝置提供的開發包集合。在
J2ME
中還有一個重要的概念是可選包(
Optional
Package
),它是針對特定裝置提供的類庫。
目前,
J2ME
中有兩個最主要的配
置,分別是
Connected Limited Devices Configuration
(
CLDC
)
和
Connected Devices Configuration
(
CDC
)。
他們是根據裝置的硬體效能進行區分的,例如處理器、記憶體容量等。
CLDC
主要針對那些資源非常受
限的裝置比如手機、
PDA
、雙工呼叫器等。而
CDC
主
要面對那些家電產品,比如機頂盒、汽車導航系統等。簡表是以配置為基礎的,例如
Mobile Information
Devices Profile
(
MIDP
)就是
CLDC
上
層的重要簡表。
CLDC
規範定義了
3
個
層級的安全機制:底層安全機制,應用層級安全機制和端對端的安全機制。在這裡有一點需要強調的是位元組碼驗證過程。
JVM
提
供了防止惡意代碼進入企業系統的服務,位元組碼驗證過程保證了應用程式不能訪問記憶體空間或使用其域外的資源。位元組碼驗證還防止應用程式重載
Java
語
言核心庫,這是一種可以用來繞過其它應用程式級安全性措施的方法。但是,由於這種操作高昂的計算開銷,
MIDP VM
不
在運行時執行完整的位元組碼驗證,而是增加了預審和機制。要求應用程式開發人員必須在把應用程式部署到行動裝置中之前,在開發平台上預先驗證類。預驗證過程
最佳化執行流,建立應用程式中包含指令目錄的堆棧映射(
stackmap
),然後將堆棧映射添加到經
預驗證的類檔案。在運行時,
MIDP VM
迅速地對位元組碼進行線性掃描,將每個有效指令與合適
的堆棧映射項相匹配。
此外在
MIDP2.0
中規定了許可和
保護域概念。應用程式通過對敏感
API
提出許可申請來試圖獲得相應的許可權。提供了信任域與非信任
域,不同的裝置提供的保護域可能是不同的,一般我們開發的
MIDlet
都是存放到非信任域的。如果
想成為可信任的
MIDlet
需要想一個可信任的組織提出認證申請。
關於更多詳細的內容可以參看
www.j2medev.com
撰
寫的《
j2me
中文教程》,裡面有對
j2me
安
全機制的詳細介紹。
3
、
Bouncy Castle Crypto API
Bouncy
Castle
是
一種用於
Java
平台的開放源碼的輕量級密碼術包。它支援大量的密碼術演算法,並提供
JCE 1.2.1
的
實現。因為
Bouncy Castle
被設計成輕量級的,所以從
J2SE
1.4
到
J2ME
(包括
MIDP
)
平台,它都可以運行。它是在
MIDP
上啟動並執行唯一完整的密碼術包。
不管
Bouncy Castle
包的功能有多強大,它有一個主要問題:缺少文檔。
不存在線上文檔,其
JavaDoc
寫得並不好。與許多其它進階密碼術包相似,
Bouncy
Castle
包廣泛使用類型多態性來將常規概念與實現演算法分開。對於初學者來說,辨認類之間的關係以及方法參數和傳回值的
正確類型是很困難的。通常,開發人員必須瀏覽一下原始碼和測試案例來研究做事的正確方法。
4
、範例程式碼
4.1
產生金鑰組
使用
RSA
演算法,產生
1024
位
長金鑰組。
public void generateRSAKeyPair () throws
Exception {
RSAPrivateCrtKeyParameters RSAprivKey =
null;
RSAKeyParameters RSApubKey = null;
SecureRandom sr = new SecureRandom();
BigInteger pubExp = new BigInteger("10001",
16);
RSAKeyGenerationParameters RSAKeyGenPara =
new
RSAKeyGenerationParameters(pubExp, sr, 1024, 80);
RSAKeyPairGenerator RSAKeyPairGen = new
RSAKeyPairGenerator();
RSAKeyPairGen.init(RSAKeyGenPara);
AsymmetricCipherKeyPair keyPair =
RSAKeyPairGen.generateKeyPair();
RSAprivKey = (RSAPrivateCrtKeyParameters)
keyPair.getPrivate();
RSApubKey = (RSAKeyParameters)
keyPair.getPublic();
}
4.2
簽名
對位元組數組簽名。
public byte[] RSASign(byte[] toSign,
CipherParameters RSAprivKey)
throws
Exception {
if (RSAprivKey == null)
throw new
Exception("Generate RSA keys first!");
SHA1Digest dig = new
SHA1Digest();
RSAEngine eng = new
RSAEngine();
PSSSigner signer = new
PSSSigner(eng, dig, 64);
signer.init(true,
RSAprivKey);
signer.update(toSign,
0, toSign.length);
return
signer.generateSignature();
}
4.3
驗證簽名
驗證簽名值。
public boolean RSAVerify(byte[] mesg,
byte[] sig, CipherParameters RSApubKey)
throws
Exception {
if (RSApubKey == null)
throw new
Exception("Generate RSA keys first!");
SHA1Digest dig = new
SHA1Digest();
RSAEngine eng = new
RSAEngine();
PSSSigner signer = new
PSSSigner(eng, dig, 64);
signer.init(false,
RSApubKey);
signer.update(mesg, 0,
mesg.length);
return
signer.verifySignature(sig);
}
4.4
加密
對字串加密,產生密文。
public byte[] RSAEncrypt(String plainText
,CipherParameters RSApubKey)
throws Exception {
byte[] rv = null;
AsymmetricBlockCipher
eng = new RSAEngine();
eng.init(true,
RSApubKey);
byte[] ptBytes =
plainText.getBytes();
rv =
eng.processBlock(ptBytes, 0, ptBytes.length);
return rv;
}
4.5
解密
對密文解密,產生原文。
public String RSADecrypt(byte[] cipherText,
CipherParameters RSAprivKey)
throws
Exception {
byte[] rv = null;
AsymmetricBlockCipher
eng = new RSAEngine();
eng.init(false,
RSAprivKey);
rv =
eng.processBlock(cipherText, 0, cipherText.length);
return new
String(rv).trim();
}
4.6
認證解析
讀
der
認證,擷取認證資訊。
public void ShowCert(byte[] cert) throws
Exception {
ByteArrayInputStream
bIn;
ASN1InputStream aIn;
bIn = new
ByteArrayInputStream(cert);
aIn = new
ASN1InputStream(bIn);
ASN1Sequence seq =
null;
seq = (ASN1Sequence)
aIn.readObject();
X509CertificateStructure
obj = new X509CertificateStructure(seq);
TBSCertificateStructure
tbsCert = obj.getTBSCertificate();
int version =
tbsCert.getVersion();
String subject =
tbsCert.getSubject().toString();
String issuer =
tbsCert.getIssuer().toString();
long serial =
tbsCert.getSerialNumber().getValue().longValue();
String sign =
tbsCert.getSignature().getObjectId().getId();
// X509 Extensions
X509Extensions ext =
tbsCert.getExtensions();
if (ext != null) {
Enumeration en =
ext.oids();
while
(en.hasMoreElements()) {
DERObjectIdentifier
oid = (DERObjectIdentifier) en
.nextElement();
X509Extension
extVal = ext.getExtension(oid);
}
}
}
5
、總結
Bouncy Castle
功能強大,支援大量的密碼演算法。特別
是提供在
MIDP
上對認證應用的處理介面,能夠滿足在行動裝置上認證應用的需求。不足之處是其文檔
太過簡單,對類之間關係和參數含義理解困難,需要去閱讀其原碼。在效能方面,主要的瓶頸是公開金鑰演算法的速度比較慢。我在
WTK2.5
上
產生
1024
位的
RSA
密鑰需要用時
2
分
鐘左右。
參考資料
l
The Bouncy Castle project
http://www.bouncycastle.org/
l
j2me
中
文教程
J2ME
開發網(
www.j2medev.com
)
l
Data
security in mobile Java applications
http://www.javaworld.com/javaworld/jw-12-2002/jw-1220-wireless.html?page=1