技术开发 频道

保护您的J2ME/MIDP应用程序

  处理摘要

  正如我早先提到的那样,为了改进性能并避免攻击造成堵塞,您实际上签署的是消息摘要而不是消息本身。清单 1 说明了如何使用 SHA1Digest 摘要引擎来计算来自一段文本消息的已编码的摘要。

  清单 1. 创建已编码的摘要

 

static public String getDigest( String mesg ) throws Exception {

  SHA1Digest digEng
= new SHA1Digest();
  
byte [] mesgBytes = mesg.getBytes();
  digEng.update( mesgBytes,
0, mesgBytes.length );
  
byte [] digest = new byte[digEng.getDigestSize()];
  digEng.doFinal(digest,
0);
  
// Encode the digest into ASCII format for XML
  return (
new String(Base64.encode(digest)));
}

  在下几节中,我们将了解如何使用 Bouncy Castle 的 DSA、ECC 和 RSA 签名引擎来签署并验证数字签名。那些签名引擎使用不同的算法和不同的密钥,并且需要不同的参数。我们还将讨论如何将安全性信息(签名、摘要和公钥)嵌入 XML 文档。最后,我将比较三个签名引擎并提出今后的改进建议。

  DSA 签名示例

  方法 DSASigUtil.generateKeys() 生成密钥对。正如我讨论过的那样,这个步骤通常由中央认证中心在脱机状态下完成,如清单 2 所示:

  清单 2. 生成密钥对

 

// Get a secure random source.
SecureRandom sr
= new SecureRandom();

// Generate DSA parameters.
DSAParametersGenerator DSAParaGen
= new DSAParametersGenerator();
DSAParaGen.init(
1024, 80, sr);

DSAPara
= DSAParaGen.generateParameters();

// Get DSA key generation parameters.
DSAKeyGenerationParameters DSAKeyGenPara
=
          
new DSAKeyGenerationParameters(sr, DSAPara);

// Generate keys.
DSAKeyPairGenerator DSAKeyPairGen
= new DSAKeyPairGenerator();
DSAKeyPairGen.init( DSAKeyGenPara );
AsymmetricCipherKeyPair keyPair
= DSAKeyPairGen.generateKeyPair();

privKey
= (DSAPrivateKeyParameters) keyPair.getPrivate();
pubKey
= (DSAPublicKeyParameters) keyPair.getPublic();

  生成的公钥以参数 Y 来描述,并且用 pubKey.getY() 方法来检索它。参数 G、P 和 Q 描述模型。类 DSAUtil 中的下列方法检索模型和密钥参数,它们是重新构造公钥对象所必需的:

  清单 3. 检索模型和密钥参数

 

public static String getG() throws Exception {
  return (
new String(Base64.encode(DSAPara.getG().toByteArray())));
}
public static String getP() throws Exception {
  return (
new String(Base64.encode(DSAPara.getP().toByteArray())));
}
public static String getQ() throws Exception {
  return (
new String(Base64.encode(DSAPara.getQ().toByteArray())));
}
public static String getY() throws Exception {
  return (
new String(Base64.encode(pubKey.getY().toByteArray())));
}

  通过使用生成的私钥,实用程序类 DSASigUtil 可以从摘要获取两部分 DSA 签名 R 和 S:

  清单 4. 检索 DSA 签名

 

static public String [] getSignature (String digest) throws Exception {
  
// Sign
  DSASigner signer
= new DSASigner();
  signer.init(
true, privKey );
  BigInteger [] sigArray
= signer.generateSignature( digest.getBytes());

  
String [] result = new String [2];
  
// Signature R
  result[
0] = new String(Base64.encode(sigArray[0].toByteArray()));
  
// Signature S
  result[
1] = new String(Base64.encode(sigArray[1].toByteArray()));

  return result;
}

  服务器将摘要、签名和密钥参数编码成 ASCII 文本格式并以 XML 数字签名格式嵌入该文本,如清单 5 所示:

  清单 5. 编码并以数字签名格式嵌入

 

<SignedMesg>
  
<mesg>Hello World</mesg>
  
<Signature>
    
<SignedInfo>
      
<SignatureMethod
        Algorithm
="http://www.w3.org/2000/09/xmldsig#dsa-sha1" />
      
<DigestValue>Ck1VqNd45QIvq3AZd8XYQLvEhtA=</DigestValue>
    
</SignedInfo>
    
<SignatureValue>
      
<R>AMfVKyIUyPGdeUCtJxU+N9kQJc2x</R>
      
<S>RwGahqpopPx//bMYXzH8dtY0lhA=</S>
    
</SignatureValue>
    
<KeyInfo>
      
<KeyValue>
        
<DSAKeyValue>
          
<G>
            FgLTXVdxKAmDQtQHkDdFF5zthKSpQhUCzRgXxz7yzxM
            OLYrRoj5D8AXdGLS
+5CzT4gu55MbO62dBfyEWKbWTIO
            6E
+CuOfa53wvqjMl67tGxc8szgWWA6ZvRwVVVmJ6wqB
            m5hNLr7q1X2eJKQ
+u3XYpFflJktOjV8O3zeEPOtsTQ=
          
</G>
          
<P>
            AOAu2WqVEKGTF8Zcxgde4vxc8f
/Z+hk8A10M0AtY2lU
            8CX54dz2MuD6hOmhqGXJxIVlV9085d9D0yHcMv2wl9V
            Vt0
/ww+aqFukCKZj9fHgZzq26nOBXMqibDo67J2vfQw
            EZMvCnyBXdS665whjzl5i7ubXu2Su
+AqsodnvG9pyYB
          
</P>
          
<Q>AMjJUZy1RnQRqe/22BS83k2Hk8VR</Q>
          
<Y>
            AM
/9leouAW7nyON24xeqibMUpVOW8RyzcdNjp9NiPdfm
            HT42BvB4JL
/cXx0tCbyHtcR5G+vALoOo7Mh3JJ+/gjx7
            sS8uHNngqx6O6dADrc9VdPvyllNDR0szLja1RTRCIy9M
            8p0dKe
/U8iotAj2zctjfbrroMu/fTOBhkvb2gVvR
        
</Y>
        
</DSAKeyValue>
      
</KeyValue>
    
</KeyInfo>
  
</Signature>
</SignedMesg>

  验证 MIDP 应用程序从 XML 文档解析出摘要、密钥参数和签名,重新构造公钥并使用下列方法来验证签名:

  清单 6. 验证签名

 

static public boolean verify (String digest,
                              
String sig_r, String sig_s,
                              
String key_g, String key_p,
                              
String key_q, String key_y ) {

  BigInteger g
= new BigInteger( Base64.decode(key_g) );
  BigInteger p
= new BigInteger( Base64.decode(key_p) );
  BigInteger q
= new BigInteger( Base64.decode(key_q) );
  BigInteger y
= new BigInteger( Base64.decode(key_y) );
  BigInteger r
= new BigInteger( Base64.decode(sig_r) );
  BigInteger s
= new BigInteger( Base64.decode(sig_s) );

  DSAParameters DSAPara
= new DSAParameters(p, q, g);
  DSAPublicKeyParameters DSAPubKeyPara
= new DSAPublicKeyParameters(y,
                                             DSAPara);

  
// Verify
  DSASigner signer
= new DSASigner();
  signer.init(
false, DSAPubKeyPara );
  
boolean result = signer.verifySignature( digest.getBytes(), r, s );
  return result;
}

  椭圆曲线 DSA 签名示例

  在 ECDSASigUtil 类中,首先定义您计划使用的椭圆曲线模型,如清单 7 所示:

  清单 7. 定义椭圆曲线模型

 

  private static BigInteger q = new
BigInteger(
"6277101735386680763835789423207666416083908700390324961279");
  
private static BigInteger a = new
BigInteger(
"fffffffffffffffffffffffffffffffefffffffffffffffc", 16);
  
private static BigInteger b = new
BigInteger(
"64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16);
  
private static BigInteger n = new
BigInteger(
"6277101735386680763835789423176059013767194773182842284081");
  
private static byte [] G =
Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012");

  ECDSASigUtil.generateKeys() 方法使用清单 7 中的模型生成随机的密钥对。正如前面提到的那样,这个步骤通常由中央认证中心在脱机状态下完成。

0
相关文章