На примере, приведенном в ECDSA подписать с BouncyCastle и проверить с помощью Crypto ++, DSAConvertSignatureFormat()
потребности byte[]
в качестве аргументов. Но то, что я получил из своего кода Java, я получил такую подпись, которая является String
:
302e021500f16529dcaddd3cec7616a3f94e157d1c28df8ea9021500997de4ae5497268c4f8eb3129abb11ca2abea9c1
Как использовать подпись Java в коде Crypto ++?
Вот код Crypto ++ в вопросе:
bool VerifyMessage( const ECDSA<ECP, SHA256>::PublicKey& key, const string& message, const string& signature )
{
bool result = false;
string signatureFromJava("302e021500cb3333768bbe3f26d7a58388015d6110c1dbad5f021500dc2ee848c72deee1542939b3e5eb2816e71bf895");
SecByteBlock signatureFromJavaByte((byte *)signatureFromJava.data(), signatureFromJava.size());
byte finalSignature[0x40];
DSAConvertSignatureFormat(finalSignature, sizeof(finalSignature), DSA_P1363,
signatureFromJavaByte, sizeof(signatureFromJavaByte), DSA_DER);
// TODO convert finalSignature to std::string// Hexa encoding version, more readable
std::string decodedSignature;
StringSource(signature, true,
new HexDecoder(
new StringSink(decodedSignature)));
StringSource(decodedSignature+message, true,
new SignatureVerificationFilter(ECDSA<ECP,SHA256>::Verifier(key),
new ArraySink((byte*)&result,
sizeof(result))));
return result;
}
Вот этот Java-код:
public static String sign(String data) throws Exception {
KeyPair keyPair = loadKeyPair(System.getProperty("user.dir"),"ECDSA");
Signature signature = Signature.getInstance("SHA256withECDSA", "BC");
signature.initSign(keyPair.getPrivate(), new SecureRandom());
byte[] message = data.getBytes();
signature.update(message);
byte[] sigBytes = signature.sign();
//verify("TEST", sigBytes);
String signatureStr = new BigInteger(1, sigBytes).toString(16);
return signatureStr;
}
Комментарий: сбой при вызове DSAConvertSignatureFormat ()
byte finalSignature[0x40]; DSAConvertSignatureFormat(finalSignature, sizeof(finalSignature), DSA_P1363, signatureFromJavaByte, sizeof(signatureFromJavaByte), DSA_DER);
Авария потому что sizeof(signatureFromJavaByte)
это размер std::string
а не длина строки. std::string
16 или около того байтов. Он состоит из 8 байтов для указателя и 8 байтов для хранения размера указанных данных. Вместо передачи 66-72 байтов в функцию, предоставляется только 16 или около того байтов.
Я думаю, что у функции есть другие проблемы, так что вы можете пойти в другом направлении.
Как использовать подпись Java в коде Crypto ++?
Вы можете использовать код, аналогичный приведенному ниже.
Вы должны использовать шаблон &str[0]
чтобы получить неконстантный указатель на первый элемент строки. Насколько я знаю, это единственный четко определенный способ получить неконстантный указатель. Все остальное может привести к неопределенному поведению.
#define LOG_TAG "MY_PRODUCT"#define LOG_DEBUG(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#define LOG_INFO(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#define LOG_WARN(...) ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
#define LOG_ERROR(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
bool VerifyMessage( const ECDSA<ECP, SHA256>::PublicKey& key, const string& message, const string& javaSignature )
{
ECDSA<ECP, SHA256>::Verifier verifier(key);
string ieeeSignature(0x40, '\0');
size_t size = DSAConvertSignatureFormat(
reinterpret_cast<byte*>(&ieeeSignature[0]), ieeeSignature.size(), DSA_P1363,
reinterpret_cast<const byte*>(&javaSignature[0]), javaSignature.size(), DSA_DER);
ASSERT(size == 0x40);
bool result = verifier.VerifyMessage(
reinterpret_cast<const byte*>(&message[0]), message.size(),
reinterpret_cast<const byte*>(&ieeeSignature[0]), ieeeSignature.size());
if (result)
LOG_INFO("VerifyMessage: verified message");
else
LOG_WARN("VerifyMessage: failed to verify message");
return result;
}
Назовите это следующим образом.
string javaSignature("302e021500cb3333768bbe3f26d7a58388015d6110c1dbad5f021500dc2ee848c72deee1542939b3e5eb2816e71bf895");
string derSignature; // Hex decoded signature
StringSource(javaSignature, true, new HexDecoder(new StringSink(derSignature)));
bool verified = VerifyMessage(key, message, derSignature);
Вы также можете добавить функцию, подобную следующей, для преобразования произвольных подписей из DER в P1363:
std::string DER2P1363(const std::string& signature)
{
std::string result;
result.resize(256);
size_t size = DSAConvertSignatureFormat(
reinterpret_cast<byte*>(&result[0]), result.size(), DSA_P1363,
reinterpret_cast<const byte*>(&signature[0]), signature.size(), DSA_DER);
result.resize(size);
return result;
}
256 — это максимальная длина строки. Он будет изменен после преобразования подписи DER.
Других решений пока нет …