M2Crypto и java.security возвращают разные подписанные сообщения

Мне трудно перенести некоторый Java-код на Python для проекта.

Следующий код Java используется для подписи псевдослучайного одноразового номера, отправляемого на сервер для проверки:

private static final String NONCE_SIGNATURE_ALGORITHM = "SHA512withRSA";

@JsonProperty
private String encodedData;

@JsonProperty
private String encodedSignedData;

@SuppressWarnings("unused")
private cacertnonceverification() {
}

public cacertnonceverification(byte[] decodedData, PrivateKey privateKey)
        throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
    byte[] decodedSignedData = sign(privateKey, decodedData);
    encodedData = Base64.getEncoder().encodeToString(decodedData);
    encodedSignedData = Base64.getEncoder().encodeToString(decodedSignedData);
}

@Override
public String toString() {
    final StringBuilder sb = new StringBuilder("CACertNonceVerificationData{");
    sb.append("encodedData='").append(encodedData).append('\'');
    sb.append(", encodedSignedData='").append(encodedSignedData).append('\'');
    sb.append('}');
    return sb.toString();
}

private byte[] sign(PrivateKey privateKey, byte[] dataBytes)
        throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
    Signature sig = Signature.getInstance(NONCE_SIGNATURE_ALGORITHM);

    sig.initSign(privateKey);
    sig.update(dataBytes);

    return sig.sign();
}

Это работает, как ожидалось, но следующий код Python возвращает другое значение для того же одноразового номера, подписанного тем же закрытым ключом. Я тестировал PyCrypto и M2Crypto - оба возвращают одно и то же значение при подписании одноразового номера, но они отличаются от возвращаемого значения Java.

def sign_nonce(nonce, privKey):

   key=EVP.load_key(privKey)
   key.reset_context(md='sha512')
   key.sign_init()
   key.sign_update(nonce.encode('utf-8'))

   return binascii.b2a_hex(key.sign_final()).decode("utf-8")

def sign_string(message, privKey):

   f = open(privKey, 'r')
   keyString = f.read()
   keyString = keyString.encode('utf-8')
   key = rsa.PrivateKey.load_pkcs1(keyString)

   return binascii.b2a_hex(rsa.sign(message.encode(), key, 'SHA-512')).decode('utf-8')

Есть идеи, что вызывает эту разницу, мне чего-то не хватает?

Спасибо!


edit: Мой сценарий Python действительно проверяет, что подписанный одноразовый номер действителен, и я использую одни и те же открытый и закрытый ключи как для кода Python, так и для кода Java, но, очевидно, получаю разные результаты для подписанного значения. Для меня это означает, что алгоритм подписи, используемый java.security и M2Crypto / RSA, отличается, но я мог бы ошибиться - я новичок в криптографии.


изменить 2: я попытался использовать M2Crypto.RSA для подписи одноразового номера и получил все еще другой ответ, но изменил код, и теперь M2Crypto EVP и RSA, и rsa выводят то же значение со знаком. По-прежнему не удалось заставить их соответствовать ожидаемому значению от Java:

Ожидаемое значение: 6d90537599b912ac0de9f68dc0d104a04c5aa74e35262f73872bb01ed1e2cc37100ff1a00735da307fa325f3e30f3c81157755fc60c7ee69bd91bf44b6a5f5e4161bdd67cf982550d992a0a16d12ed5ea30b878a8b2f8eee61cf64e083d7b74a635dabba44bf0b51b9b305aa901b3d090712ee3994057b076d53366a3a387de0f7b2e220cf11239facfce0df6d9a54dfb365f7d3996ea20b55ec75e3661cf95392eda75696cfc6bebda304a2671428dad38a43d5a579550595fe9180539b2b7eb3d568a1f8ce05ded2ae3241a732fffd1404f989eea3e68dda6cd13bfcd6b2e47e64685763a6c3c0f1c47f84c908e22e718254b9f46a7a1de7e2280ccb59c1c5

M2Crypto RSA: 2c973dd7006c058293787504203e36e921ae286f44bcdbf2bd4b48c8a7d9a73723c058d1bcd15b76f6a7145d55cf6109f4bbe5f3953d953177117ef4733e4d3ac22e8a4d320ae6c3a626ddce2a3d5db6b0f10656dd49179c3d60ba912bf21b2e2eac5def74aa6809b74d7711cbb86d719b1fe4df5b7215067af34de3e03859e2c919587bc7f00ec96c6b678c5fc8e114cebae3f5d301811dacc247cd2df9dadf62bccd524147f582f77f0ce29077c7352c8b9893056dce3d65de44d0fc45b88363db9df59c142a01d8f32bf48f05183757e3cd0954c528a7601f4edb56ed9175b219e08aa79514694aedff45bbb365e7d54e534973f6a2aa9f22da12890bbbb5

M2Crypto EVP: 2c973dd7006c058293787504203e36e921ae286f44bcdbf2bd4b48c8a7d9a73723c058d1bcd15b76f6a7145d55cf6109f4bbe5f3953d953177117ef4733e4d3ac22e8a4d320ae6c3a626ddce2a3d5db6b0f10656dd49179c3d60ba912bf21b2e2eac5def74aa6809b74d7711cbb86d719b1fe4df5b7215067af34de3e03859e2c919587bc7f00ec96c6b678c5fc8e114cebae3f5d301811dacc247cd2df9dadf62bccd524147f582f77f0ce29077c7352c8b9893056dce3d65de44d0fc45b88363db9df59c142a01d8f32bf48f05183757e3cd0954c528a7601f4edb56ed9175b219e08aa79514694aedff45bbb365e7d54e534973f6a2aa9f22da12890bbbb5

RSA: 2c973dd7006c058293787504203e36e921ae286f44bcdbf2bd4b48c8a7d9a73723c058d1bcd15b76f6a7145d55cf6109f4bbe5f3953d953177117ef4733e4d3ac22e8a4d320ae6c3a626ddce2a3d5db6b0f10656dd49179c3d60ba912bf21b2e2eac5def74aa6809b74d7711cbb86d719b1fe4df5b7215067af34de3e03859e2c919587bc7f00ec96c6b678c5fc8e114cebae3f5d301811dacc247cd2df9dadf62bccd524147f582f77f0ce29077c7352c8b9893056dce3d65de44d0fc45b88363db9df59c142a01d8f32bf48f05183757e3cd0954c528a7601f4edb56ed9175b219e08aa79514694aedff45bbb365e7d54e534973f6a2aa9f22da12890bbbb5


person Jesse    schedule 19.09.2018    source источник
comment
Вы работаете в Windows? Вы пробовали указать также UTF-8 на Java? Я сталкивался с этой (немного сложной) проблемой много раз O :)   -  person x80486    schedule 19.09.2018
comment
Я работаю на Mac, код Java - это стандарт, которому я должен соответствовать. Я попробую удалить кодировку UTF-8 в Python, чтобы посмотреть, влияет ли она на вывод.   -  person Jesse    schedule 19.09.2018


Ответы (1)


Мне удалось решить проблему, используя модули EVP и RSA вместе, чтобы подписать мой одноразовый номер:

key = RSA.load_key(privKey)
md = EVP.MessageDigest('sha512')
md.update(message)
digest=md.final()
signature = key.sign(digest, "sha512")

return b64encode(signature).decode('utf-8') 
person Jesse    schedule 01.10.2018