Конвертировать Java в подпись Python DSA - PullRequest
2 голосов
/ 15 августа 2011

Кто-нибудь знает, как мне конвертировать этот 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 ]

3 голосов
/ 29 августа 2011

Подпись DSA определяется как пара целых чисел (называемых r и s соответственно). Стандарт DSA не предписывает конкретное кодирование такой подписи в последовательность байтов. Таким образом, каждый протокол, использующий подписи DSA, должен определять свою собственную кодировку.

Существует два обычно используемых кодировки подписи DSA; одним из них является прямая конкатенация беззнаковых кодирований с прямым порядком байтов значений r и s , оба из которых нормализуются к длине (в байтах) q параметр в открытом ключе («размер подгруппы», обычно 160-битное простое число, что дает 40-байтовую подпись). Документация к M2Crypto.DSA довольно краткая, но я предполагаю, что она возвращает r и s отдельно, но уже в этом формате.

Java использует другую кодировку, основанную на ASN.1. Эта кодировка используется в X.509 и во всем, что на ней основано (включая подписи в SSL / TLS). ASN.1 является общим стандартом для представления и сериализации структурированных данных. В этом случае подпись должна быть сериализацией ASN.1 SEQUENCE, содержащей два значения INTEGER ( r и s , в этом порядке). В соответствии с правилами кодирования ASN.1 и DER подпись должна иметь следующий формат:

0x30 A 0x02 B R 0x02 C S

где:

  • R - это кодировка с прямым порядком байтов со знаком r минимальной длины: это означает, что первый байт должен иметь значение между 0 и 127, и он должен иметь значение 0 только в том случае, если второй байт имеет значение между 128 и 255. Другими словами, кодируйте r как последовательность байтов с условным порядком байтов (самый старший байт во-первых), убедившись, что у вас как можно меньше начальных нулевых битов, при условии, что вы сохраняете хотя бы один (это то, что означает «подписанное» кодирование: поскольку r положительно, его старший значащий бит должен быть 0). Поскольку r является целым числом от 0 до q-1 , длина R будет не более чем на один байт больше длины q , но оно может быть меньше.

  • S - кодировка со знаком с прямым порядком байтов s (такая же обработка, как для r ; примечание: R и S может иметь различную длину).

  • B - это один байт, содержащий длину R (в байтах).

  • C - это один байт, содержащий длину S (в байтах).

  • A - это один байт, содержащий B + C + 2 (т. Е. Длину в байтах того, что следует за байтом A ) .

Написание специализированных функций кодирования и декодирования для подписей DSA на основе ASN.1 немного утомительно, но не сложно; просто позаботьтесь о создании последовательностей R и S нужного размера. В качестве альтернативы вы можете использовать существующую библиотеку кодирования / декодирования ASN.1, которая излишня, но может быть проще, в зависимости от вашей ситуации.

1 голос
/ 16 августа 2011

Согласно http://download.oracle.com/javase/1.5.0/docs/guide/security/CryptoSpec.html#AppB (по какой-то странной причине, в которой есть два Приложения B, и вам нужно прокрутить до второго) Java использует кодировку ASN.1 SEQUENCE ::= { r INTEGER, s INTEGER }

быть в состоянии генерировать (и анализировать) это в Python, используя pyasn1 - http://pyasn1.sourceforge.net/

ASN.1 является стандартом для кодирования двоичных данных.Таким образом, приведенная выше информация указывает, как код Java объединяет два значения, которые возвращает код Python.Поэтому вы можете сделать то же самое, и, таким образом, поддерживать тот же формат байтов для подписи.

...