将Java转换为python DSA签名

时间:2011-08-15 18:07:19

标签: java python public-key-encryption dsa

有谁知道如何将这个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字节字符串的元组,我不知道该怎么做。

2 个答案:

答案 0 :(得分:3)

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

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

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

0x30 A 0x02 B R 0x02 C S

其中:

  • R r 的big-endian 签名编码,长度最小:这意味着第一个字节应该有0到127之间的值,仅当第二个字节的值介于128和255之间时,它才应为0。换句话说,将 r 编码为具有big-endian约定的字节序列(最重要的字节是第一个),确保你有尽可能少的前导零位,前提是你保留至少一个(这是“签名”编码的意思:因为 r 是正数,其最重要的位必须为0)。由于 r 0 q-1 之间的整数,因此 R 的长度最多为一个字节大于 q 的长度,但它可以更小。

  • S s 的big-endian签名编码(与 r 相同的处理方式;注意: R S 可能有不同的长度。)

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

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

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

为基于ASN.1的DSA签名编写专门的编码和解码功能有点乏味但并不难;只需要处理正确大小的 R S 序列。或者,您可以使用现有的ASN.1编码/解码库,这可能更容易,但可能更容易,具体取决于您的情况。

答案 1 :(得分: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代码返回的两个值。因此,您可以这样做,因此保持签名的相同字节格式。