1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 22:58:11 +00:00
serenity/Userland/Libraries/LibCrypto/PK/Code/EMSA_PKCS1_V1_5.h
Michiel Visser be138474c5 LibCrypto: Add EMSA-PKCS1-V1_5 encoder and verification
This add an implementation for the EMSA-PKCS1-V1_5-ENCODE function from
RFC8017 section 9.2. The verification of this encoding is implemented by
simply encoding the message to be verified, and then comparing the two
encoded string.

The digest info for the different hash function is from RFC8017 section
9.2 notes 1. These byte sequences are actually ASN.1 encoded data,
however these are always constant for a specific hash function and can
be treated as opaque byte sequences.
2022-02-23 13:20:28 +03:30

120 lines
3.8 KiB
C++

/*
* Copyright (c) 2022, Michiel Visser <opensource@webmichiel.nl>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Array.h>
#include <AK/Format.h>
#include <AK/Random.h>
#include <AK/Vector.h>
#include <LibCrypto/Hash/MD5.h>
#include <LibCrypto/Hash/SHA1.h>
#include <LibCrypto/Hash/SHA2.h>
#include <LibCrypto/PK/Code/Code.h>
namespace Crypto {
namespace PK {
template<typename HashFunction>
class EMSA_PKCS1_V1_5 : public Code<HashFunction> {
public:
template<typename... Args>
EMSA_PKCS1_V1_5(Args... args)
: Code<HashFunction>(args...)
{
}
virtual void encode(ReadonlyBytes in, ByteBuffer& out, size_t em_bits) override
{
auto& hash_fn = this->hasher();
hash_fn.update(in);
auto message_digest = hash_fn.digest();
auto message_digest_size = message_digest.bytes().size();
auto digest_info = hash_function_digest_info();
auto encoded_message_length = digest_info.size() + message_digest_size;
auto em_bytes = (em_bits + 7) / 8;
// RFC8017 section 9.2: 3. If emLen < tLen + 11, output "intended encoded message length too short" and stop.
if (em_bytes < encoded_message_length + 11) {
dbgln("EMSA-PKCS1-V1_5-ENCODE: intended encoded message length too short");
return;
}
auto offset = 0;
// Build the padding 0x0001ffff..ff00
out[offset++] = 0x00;
out[offset++] = 0x01;
for (size_t i = 0; i < em_bytes - encoded_message_length - 3; i++)
out[offset++] = 0xff;
out[offset++] = 0x00;
// Add the digest info and message digest
out.overwrite(offset, digest_info.data(), digest_info.size());
offset += digest_info.size();
out.overwrite(offset, message_digest.immutable_data(), message_digest.data_length());
}
virtual VerificationConsistency verify(ReadonlyBytes msg, ReadonlyBytes emsg, size_t em_bits) override
{
auto em_bytes = (em_bits + 7) / 8;
auto buffer_result = ByteBuffer::create_uninitialized(em_bytes);
if (buffer_result.is_error()) {
dbgln("EMSA-PKCS1-V1_5-VERIFY: out of memory");
return VerificationConsistency::Inconsistent;
}
auto buffer = buffer_result.release_value();
// Encode the supplied message into the buffer
encode(msg, buffer, em_bits);
// Check that the expected message matches the encoded original message
if (emsg != buffer) {
return VerificationConsistency::Inconsistent;
}
return VerificationConsistency::Consistent;
}
private:
inline ReadonlyBytes hash_function_digest_info();
};
template<>
inline ReadonlyBytes EMSA_PKCS1_V1_5<Crypto::Hash::MD5>::hash_function_digest_info()
{
// RFC8017 section 9.2 notes 1
return { "\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10", 18 };
}
template<>
inline ReadonlyBytes EMSA_PKCS1_V1_5<Crypto::Hash::SHA1>::hash_function_digest_info()
{
// RFC8017 section 9.2 notes 1
return { "\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14", 15 };
}
template<>
inline ReadonlyBytes EMSA_PKCS1_V1_5<Crypto::Hash::SHA256>::hash_function_digest_info()
{
// RFC8017 section 9.2 notes 1
return { "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19 };
}
template<>
inline ReadonlyBytes EMSA_PKCS1_V1_5<Crypto::Hash::SHA384>::hash_function_digest_info()
{
// RFC8017 section 9.2 notes 1
return { "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30", 19 };
}
template<>
inline ReadonlyBytes EMSA_PKCS1_V1_5<Crypto::Hash::SHA512>::hash_function_digest_info()
{
// RFC8017 section 9.2 notes 1
return { "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40", 19 };
}
}
}