2

有谁知道我将如何将此java代码转换为python?

/**
* signs the data for the account account
*/
private byte[] sign(String pkStr,byte[] data, String keyType) throws Exception {
    BASE64Decoder decoder = new BASE64Decoder();
    KeyFactory keyFac = null;
    //instantiate the key factory based on the key alg type
    if(keyType.equals("DSA")){
        keyFac = KeyFactory.getInstance("DSA");
    }else if(keyType.equals("RSA")){
        keyFac = KeyFactory.getInstance("RSA");
    }

    //generate the public key
    PKCS8EncodedKeySpec dprks = new PKCS8EncodedKeySpec(decoder.decodeBuffer(pkStr));
    PrivateKey pk = keyFac.generatePrivate(dprks);

    return(signBytes(data,pk,keyType));
}

    /**
* sign the data with the key
*/
private byte[] signBytes(byte [] data,
    PrivateKey signingPrivateKey, String keyType)throws Exception {

    Signature dsa = null;
    //instantiate the signature alg based on the key type
    if(keyType.equals("DSA")){
        dsa = Signature.getInstance("SHA1withDSA");
    }else if(keyType.equals("RSA")){
        dsa = Signature.getInstance("SHA1withRSA");
    }
    /* Initializing the object with a private key */
    dsa.initSign(signingPrivateKey);

    /* Update and sign the data */
    dsa.update(data);
    byte[] sig = dsa.sign();
    return sig;
}

“keyType”似乎总是作为“DSA”传递,所以我查看了M2Crypto.DSA,这看起来很有希望。然而,DSA.sign 函数返回一个 2 字节字符串的元组,我完全不确定如何处理。

4

2 回答 2

3

DSA 签名被定义为一对整数(分别称为rs)。DSA 标准不要求将这种签名特定编码为字节序列。因此,每个使用 DSA 签名的协议都必须定义自己的编码。

常用的DSA签名编码有两种;一种是rs值的大端无符号编码的直接连接,两者都被归一化为公钥中q参数的长度(以字节为单位)(“子组大小”,通常是 160 位素数)整数,从而产生一个 40 字节的签名)。M2Crypto.DSA 的文档非常简洁,但我的猜测是它分别返回rs但已经采用该格式。

Java 使用基于 ASN.1 的另一种编码。这是在 X.509 和任何基于它的东西(包括 SSL/TLS 中的签名)中使用的编码。ASN.1 是结构化数据表示和序列化的通用标准。在这种情况下,签名应该是SEQUENCE包含两个INTEGER值(rs,按此顺序)的 ASN.1 的序列化。根据 ASN.1 和 DER 编码规则,签名应具有以下格式:

0x30 A 0x02 BR 0x02 CS

在哪里:

  • R是r的最小长度的大端有符号编码:这意味着第一个字节的值应介于 0 和 127 之间,只有当第二个字节的值介于 128 和 255 之间时,它的值才应为 0。换句话说,将r编码为具有大端约定的字节序列(最重要的字节首先出现),确保您有尽可能少的前导零位,前提是您至少保留一个(这就是“有符号" 编码的意思是:因为r是正数,所以它的最高有效位必须是 0)。由于r是介于0q-1之间的整数,因此R的长度最多比q的长度多一个字节,但它可以更小。

  • S是s的大端有符号编码(与r的处理相同;注意:RS可能有不同的长度)。

  • B是包含R长度(以字节为单位)的单个字节。

  • C是包含S长度(以字节为单位)的单个字节。

  • A是包含B+C+2的单个字节(即字节A后面的长度,以字节为单位)。

为基于 ASN.1 的 DSA 签名编写专门的编码和解码函数有点乏味但并不难;只需注意生成正确大小的RS序列。或者,您可以使用现有的 ASN.1 编码/解码库,这有点矫枉过正,但可能更容易,具体取决于您的情况。

于 2011-08-29T01:58:52.483 回答
1

根据http://download.oracle.com/javase/1.5.0/docs/guide/security/CryptoSpec.html#AppB(出于某些奇怪的原因,有两个附录 B,您需要向下滚动到第二个) Java 使用 ASN.1 编码SEQUENCE ::= { r INTEGER, s INTEGER }

您应该能够使用 pyasn1 在 Python 中生成(和解析)它 - http://pyasn1.sourceforge.net/

ASN.1 是一种编码二进制数据的标准。因此,上面的信息指定了 Java 代码如何组合 Python 代码返回的两个值。因此,您可以这样做,从而为签名保持相同的字节格式。

于 2011-08-15T21:01:27.197 回答