#include <gtest/gtest.h>

#include <userver/crypto/public_key.hpp>
#include <userver/crypto/signers.hpp>
#include <userver/crypto/verifiers.hpp>

USERVER_NAMESPACE_BEGIN

namespace {

// Private key used here:
//
// -----BEGIN RSA PRIVATE KEY-----
// Proc-Type: 4,ENCRYPTED
// DEK-Info: DES-EDE3-CBC,B8D262FB25A12F01
//
// 8S+YvinHEJLy3tAN6gJIff6EOptIi+5TUMpcFArm/wvCokbYruAbY7ykomkLNIYj
// LCFS7/HqlddGAO1W3up5MtlPFFFcWW1xD+tu6IhIxnq5kjCosa5r1FC8H55wqAew
// rUV6I7yOhHAuBTLkWplO8JE5i43+VZ5emWLiE7utgt8867kznJ40KSbxI8iSf+QR
// yO8WFzBnmcqKA/gE/a0ukZcSFpCXa5vPwpp+dC2utpUE76u0r2AbAih9rOpnIAvo
// +DLyVGcSWV/wszvTE8dCoUuOMOZuakXl9nL3ZjSFmZaEEJO94dxObO0Z/N5cWy3l
// Q9rQENlAx7u1Ja1zryIJUD7Qb3Fy1Oo94x7HAtuJlbbXL0lrgUA6zi3z7ZqsDPMp
// puJCGYS2qmmppeNz+x2hCd3E2z1GvJRQWoDeTpuwPC0HdE/T1bg/5aqzCxfGmi/e
// /cHhH1wvdgIJCQ4Qxp6HkXu+b6Kak8kKUgWKCJjpv6a8iA7i8qV4uxaNdzVMxiQL
// L107kEyXMbpLjirgSqLhCjQNZztl7caKhcClkgprfILs234JPlcWmVCOqoPOL3fa
// 0IWionOG8fgoo2oa2L2urELMCBOUPRPADAsrzCorKjwIZQrDXKDmrgok4oBIVq5n
// ojKRBPKrXS6GugXnOBIHKnhc3Gj4zoHQqbDHBG6wCkKexAj/pzNiayufheFQMIxW
// 08L5/d2yDzvcuZE9fJ7LsYz6436q8k00UC+m3mW9N9UHSbheF7nMt8cGmgRn7e+S
// Bh3+lxHy1gCYsQpkXYnR/COdUaJm1UDVNLfnwcWJCB3vvMpERyjtg/l/gU7Rqnq6
// 954oAZY+sbPGnjHruQ0d79W8bVYE4pboG6+0Sza5rOC25LvC0LDoCe4jB6n0gxx9
// XlNDnk2xCsdJaZm2ULcH6UBr9GlShB5P4j3rsI2sNxGYk1neclwghKCMTUNznwZo
// 9oIbxk+ZgFX7AmWEj2hDPUENJ4bXceHaKnOFthFa21kzzlI49cdB6LXKq292L80t
// Zvs/rOkfM8tHKvbEkCRBp5J/lKok5QVyc1a94C4K4gu7EK2LKswBj4pcPIeAE9EZ
// zB5zP6dVtF7HK6w2BCRbnrLNXLjsq6TikzvkKblWrmwHMdNKMOXzARtUMZR9SIOr
// VAprsSQEr6SlOcHaYFMTTEu271BL8KmENqR/7klikljr7b6+SDKd4sA/HSGJKAkv
// NVnHu/sionG4109CwvB6PiDFyKTC2HKZLeHnd/6Sj1d05x3IKeP1D3GsnGaoD09D
// JtHHNesAQQkkG+th6k1G8eUtTcgHzXHaChj9j13gbU4defGAurgnWuBHV31eg1RX
// wb5DwR947jDWDR19YgLXERi2N4P49BkVZm5sT1ibwO1DptxxmYn837m2j8wY1F0O
// G4U9YKHbET0ZzdYJGTNUmf9T2UOj0YHCRCk2M86ZYV7Da4TKoJKrQpHKUbcYS13n
// m3QUmCixxck+3DVdH3sI39CH4q3gE1f3/GZIRZEwxjSQHvCwWvkBjjOrFo9Fx/ma
// 0+E4DC0t8i9doIrvhFp4VkSvOLgWSK5DFUriOVg5VyFlI84rG3O5uZGFRvYG1eQC
// -----END RSA PRIVATE KEY-----

using namespace std::literals::string_view_literals;

constexpr crypto::PublicKey::ModulusView kModulus{
    "\x00\xce\x14\xba\x46\xd9\xc2\x43\xbf\x82\x56\x52\x69\x72\x10\x55\x35\x2a"sv
    "\x39\x80\x8c\xcc\xad\xe3\x41\xab\x22\x45\xf1\xc6\x35\xa2\x0a\x7d\x9b\x20"sv
    "\xc9\x77\xa8\xce\x45\x39\x1b\x50\xd0\x81\x02\x47\xf5\x95\x67\xe8\x81\x44"sv
    "\x99\x58\x0c\x7b\xc3\x89\x52\x99\xcc\x43\x58\xbc\xc6\xc1\xeb\xe5\x85\xd8"sv
    "\x1a\x3c\x00\xdf\x64\x40\x34\x1e\x46\xc8\xe0\x41\x49\x60\x7f\xe4\xef\x86"sv
    "\x9f\xd8\xac\xca\x9e\xd2\xd5\xbb\x1b\xca\xae\x9a\x1b\x1a\xe3\xa6\xf8\xc2"sv
    "\x90\xd9\x74\x0c\xb6\x45\x90\x58\x05\xd4\xc1\x65\x80\x18\xa2\xda\x53\xd2"sv
    "\x9e\x11\x58\xb4\xf0\x64\x2a\x00\x2f\x20\xe5\xa7\x97\xac\x4a\xed\x19\x0d"sv
    "\xca\x27\x31\x05\x85\xfd\xf3\x1f\xd2\x3c\x16\xa4\x89\x5f\x72\x58\xbd\xd8"sv
    "\x9d\x04\x12\x33\x0c\x62\x8a\x30\x4e\xfa\x2f\xeb\xfe\x97\x0e\xfe\x7f\x11"sv
    "\x96\x74\x88\x06\x58\xc9\xca\xe7\x10\x12\x93\xd5\x61\x89\x9b\xb6\x9a\x9e"sv
    "\x5b\xb6\xc8\x8a\x45\xb2\xb4\x78\x6d\x8a\xda\xc4\x6c\x6a\x3c\x1d\xc7\x8a"sv
    "\xf3\x19\x36\x8e\x9b\xdb\xc0\x6b\x4e\x2d\x83\x8f\xb0\x1a\x55\xb3\x62\x42"sv
    "\x9b\x61\xc6\x5b\xbe\x3f\x87\x2a\xb8\xc3\x65\x44\x96\x8e\xe1\xcb\xd2\x3a"sv
    "\x07\xfb\x04\xc1\x17"sv};
constexpr crypto::PublicKey::ExponentView kExponent{"\x01\x00\x01"sv};

}  // namespace

TEST(Crypto, VerifyRsaFromComponents256) {
    const auto pub_key = crypto::PublicKey::LoadRSAFromComponents(kModulus, kExponent);

    const crypto::VerifierRs256 verifier{pub_key};
    const auto sign =
        "\xbb\xbc\x56\x57\x0e\x36\x6b\x7b\xea\x57\xfe\xfb\xa4\x64\x3a\x42\xc6\xe7"sv
        "\xa9\xca\x45\x17\x2d\x5f\xbc\x4c\x3e\xba\xba\x94\xf1\x7f\xdc\x7f\xf1\x86"sv
        "\x89\x23\x82\xd5\x24\x85\xcd\x26\x26\x26\x8b\xf8\x90\x13\x9a\x3a\x4d\x38"sv
        "\x9b\x88\xfe\x13\xfa\x13\x20\x69\xc8\xfc\x3f\x89\x3d\xde\x28\x72\xc0\xbc"sv
        "\xf3\xb2\x92\x9f\x8b\x39\x36\xa1\x2c\xc6\x16\x19\xe9\x62\x02\x16\xa8\xf8"sv
        "\x86\x15\x67\x68\x96\x90\xae\xf6\xc3\xb9\x9e\xcb\xeb\x64\xe3\x43\x2e\x12"sv
        "\xad\x3e\xda\xfc\x0c\x4e\xf1\x59\x1a\x6e\x6d\x8f\x75\xa2\xa9\x6c\x9a\xa7"sv
        "\x17\x68\x8d\xe9\x00\x3a\xa2\xf5\xe7\xb6\xee\xd0\xde\xfe\x01\xa5\x4f\x51"sv
        "\x54\x19\x35\x28\xe7\x6b\xc9\xe1\xaa\xe5\x56\x15\xa5\x2a\x7d\xf8\x62\x64"sv
        "\x25\x12\xcd\x57\xf6\xed\x15\xfa\xf8\xd4\x54\xa5\x0f\xaf\xa2\x86\xdb\xc2"sv
        "\xf9\xf2\x6a\x53\xaa\x5d\x61\x2c\x1c\x2b\xa7\x31\xfd\x00\x75\x04\xc1\x44"sv
        "\x17\xc0\xd5\x96\xe5\x16\xa7\x8a\xe8\x1b\x97\x53\x31\xae\xb1\xc5\x86\x16"sv
        "\xff\x94\xda\x75\x63\xdf\x04\xc3\x18\xd5\x3e\x83\xcd\x51\xfa\xaa\x86\x04"sv
        "\x6b\x78\xb0\x48\xf3\xfa\x4a\x8d\x07\x39\x2e\x55\xb7\xe3\xd3\x57\xef\xef"sv
        "\xce\x71\xd0\xc4"sv;
    EXPECT_NO_THROW(verifier.Verify({"Hello Kitty\n"}, sign));
    EXPECT_THROW(verifier.Verify({"Hello, Kitty"}, sign), crypto::VerificationError);
}

TEST(Crypto, VerifyRsaFromComponents512) {
    const auto pub_key = crypto::PublicKey::LoadRSAFromComponents(kModulus, kExponent);

    const crypto::VerifierRs512 verifier{pub_key};
    const auto sign =
        "\x39\xfa\x79\xbf\xe2\xe0\xd2\xbc\x45\x2e\x69\x3e\x07\x52\xc1\xb1\x5c\x23"sv
        "\xeb\xef\x9a\xdc\x23\xd2\xb0\xb8\x2f\x06\x7c\xf6\xcf\x3f\x9d\x15\x59\x3a"sv
        "\x4a\x9e\x66\x40\x29\xbe\xfb\x72\x69\x8a\x9d\xef\xdd\x4c\x07\xca\x48\xc1"sv
        "\xdf\x16\xd7\xf7\x10\x8d\xb1\xec\xde\x00\x08\x67\xdc\xb7\xae\xc4\x2c\xc3"sv
        "\x3b\xf1\xe6\x20\x73\x55\xc7\x0a\x3f\x3c\x41\x41\xb9\xac\xb0\x7e\x65\x2a"sv
        "\xa1\x8b\x6e\xd6\x5f\x79\x17\x62\xef\x61\x2d\xbe\xfb\x5e\x68\x04\x2a\x23"sv
        "\x70\x2f\x23\x6e\xc5\xb4\x21\x63\x86\x57\xd4\x0b\xbe\x35\xc9\x43\x03\xf2"sv
        "\xf1\xd1\xdd\xde\xa5\x92\xd5\xfd\x34\x64\x1d\xeb\x73\xa5\x84\xf0\x99\x89"sv
        "\x03\xcc\xe7\xe6\x4c\xfc\xba\x1e\xd5\xe4\xaa\x70\xa0\x31\xc1\xce\x7f\x22"sv
        "\xb2\x04\xcc\x94\xaf\x47\x87\x1f\x5b\xde\x9a\x57\xcb\xc4\x14\x97\xe7\x10"sv
        "\x64\xc2\x57\x05\x83\x34\x43\xa8\x1c\x30\x54\x89\x45\x79\xa0\x44\x86\xe8"sv
        "\x9d\x1f\x2a\x23\xc0\x1f\x4a\x93\x6e\x3e\x21\x9f\x7a\x6d\x7f\x89\x03\x31"sv
        "\xf8\xb9\xf1\xb1\xc6\xd1\xb7\x68\x7e\x9a\x7c\xf7\x89\x9f\x35\x5c\xe6\xde"sv
        "\x99\x08\x25\x47\x42\xc7\xd3\xc8\x5b\x09\x48\xf2\x48\xa1\xba\x50\x12\x38"sv
        "\xa8\xd5\xf5\x50"sv;
    EXPECT_NO_THROW(verifier.Verify({"Hello, World!\n"}, sign));
    EXPECT_THROW(verifier.Verify({"Hello, Kitty"}, sign), crypto::VerificationError);
}

namespace {

constexpr crypto::PublicKey::CurveTypeView kType{"P-256"};
constexpr auto ecdsa256v1_priv_key = R"(
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgXBhZSD1+ClYPr7OU
i9mTKIxHwWeXX0D1OU0vj+UVG5ahRANCAARZy8MWHqCFyM04NMK+9chTuhSOLIWV
8hAE4TNtO1Iv96ncPhAtDmadYJh/D3fcojN5U5BG56dKd5y497Hoq9KD
-----END PRIVATE KEY-----
)";
constexpr crypto::PublicKey::CoordinateView kX{
    "\x59\xcb\xc3\x16\x1e\xa0\x85\xc8\xcd\x38\x34\xc2\xbe\xf5"sv
    "\xc8\x53\xba\x14\x8e\x2c\x85\x95\xf2\x10\x04\xe1\x33\x6d"sv
    "\x3b\x52\x2f\xf7"sv};
constexpr crypto::PublicKey::CoordinateView kY{
    "\xa9\xdc\x3e\x10\x2d\x0e\x66\x9d\x60\x98\x7f\x0f\x77\xdc"sv
    "\xa2\x33\x79\x53\x90\x46\xe7\xa7\x4a\x77\x9c\xb8\xf7\xb1"sv
    "\xe8\xab\xd2\x83"sv};

}  // namespace

TEST(Crypto, EcdsaVerifierFromComponents) {
    crypto::SignerEs256 signer(ecdsa256v1_priv_key);
    const auto sign = signer.Sign({"Hello, World"});

    const auto pub_key = crypto::PublicKey::LoadECFromComponents(kType, kX, kY);
    const crypto::VerifierEs256 verifier{pub_key};

    EXPECT_NO_THROW(verifier.Verify({"Hello, World"}, sign));
    EXPECT_THROW(verifier.Verify({"Hello World!"}, sign), crypto::VerificationError);
}

USERVER_NAMESPACE_END
