-module(ywt_ffi). -export([verify/3, sign/2, generate_hmac/1, generate_ecdsa/2, generate_rsa/3]). -include_lib("public_key/include/public_key.hrl"). -include_lib("ywt_core/include/ywt@verify_key_VerifyEcdsa.hrl"). -include_lib("ywt_core/include/ywt@verify_key_VerifyRsa.hrl"). -include_lib("ywt_core/include/ywt@verify_key_VerifyHmac.hrl"). -include_lib("ywt_core/include/ywt@sign_key_SignEcdsa.hrl"). -include_lib("ywt_core/include/ywt@sign_key_SignRsaSimple.hrl"). -include_lib("ywt_core/include/ywt@sign_key_SignRsaFull.hrl"). -include_lib("ywt_core/include/ywt@sign_key_SignHmac.hrl"). verify(Message, Signature, #verify_ecdsa{curve = Curve, digest_type = DigestType, public_key = PublicKey}) -> % 2. Split the 64-octet sequence into two 32-octet sequences. The % first octet sequence represents R and the second S. The values R % and S are represented as octet sequences using the Integer-to- % OctetString Conversion defined in Section 2.3.7 of SEC1 [SEC1] % (in big-endian octet order). {RBin, SBin} = split_binary(Signature, byte_size(Signature) div 2), R = crypto:bytes_to_integer(RBin), S = crypto:bytes_to_integer(SBin), % 3. Submit the JWS Signing Input, R, S, and the public key (x, y) to % the ECDSA P-256 SHA-256 validator. DerSignature = public_key:der_encode('ECDSA-Sig-Value', #'ECDSA-Sig-Value'{r = R, s = S}), Params = {#'ECPoint'{point = PublicKey}, {namedCurve, Curve}}, try public_key:verify(Message, DigestType, DerSignature, Params) catch _:_ -> false end; verify(Message, Signature, #verify_rsa{digest_type = {some, D}, exponent = E, modulus = N, padding = {some, P}}) -> PublicKey = #'RSAPublicKey'{modulus = N, publicExponent = E}, try public_key:verify(Message, D, Signature, PublicKey, [{rsa_padding, P}]) catch _:_ -> false end; verify(_Message, _Signature, #verify_rsa{}) -> false; verify(Message, Signature, #verify_hmac{digest_type = DigestType, secret = Secret}) -> try crypto:hash_equals( crypto:mac(hmac, DigestType, Secret, Message), Signature) catch _:_ -> false end. sign(Message, #sign_ecdsa{curve = Curve, digest_type = DigestType, public_key = PublicKey, private_key = PrivateKey}) -> % 1. Generate a digital signature of the JWS Signing Input using ECDSA % P-256 SHA-256 with the desired private key. The output will be % the pair (R, S), where R and S are 256-bit unsigned integers. DerSignature = public_key:sign(Message, DigestType, #'ECPrivateKey'{version = 1, privateKey = PrivateKey, parameters = {namedCurve, Curve}, publicKey = PublicKey}), #'ECDSA-Sig-Value'{r = R, s = S} = public_key:der_decode('ECDSA-Sig-Value', DerSignature), % 2. Turn R and S into octet sequences in big-endian order, with each % array being be 32 octets long. The octet sequence % representations MUST NOT be shortened to omit any leading zero % octets contained in the values. RSSize = ywt@internal@core:named_curve_size(Curve) * 8, % 3. Concatenate the two octet sequences in the order R and then S. % (Note that many ECDSA implementations will directly produce this % concatenation as their output.) <>; sign(Message, #sign_rsa_simple{digest_type = DigestType, public_exponent = E, modulus = N, private_exponent = D, padding = Padding}) -> public_key:sign(Message, DigestType, #'RSAPrivateKey'{version = 'two-prime', modulus = N, publicExponent = E, privateExponent = D, otherPrimeInfos = asn1_NOVALUE}, [{rsa_padding, Padding}]); sign(Message, #sign_rsa_full{digest_type = DigestType, public_exponent = E, modulus = N, private_exponent = D, first_prime_factor = P, second_prime_factor = Q, first_factor_crt_exponent = DP, second_factor_crt_exponent = DQ, first_crt_coefficient = QI, other_primes_info = Oth, padding = Padding}) -> Others = case Oth of [] -> asn1_NOVALUE; _ -> lists:map(fun({R, D@2, T}) -> #'OtherPrimeInfo'{prime = R, exponent = D@2, coefficient = T} end, Oth) end, public_key:sign(Message, DigestType, #'RSAPrivateKey'{version = 'two-prime', modulus = N, publicExponent = E, privateExponent = D, prime1 = P, prime2 = Q, exponent1 = DP, exponent2 = DQ, coefficient = QI, otherPrimeInfos = Others}, [{rsa_padding, Padding}]); sign(Message, #sign_hmac{digest_type = DigestType, secret = Secret}) -> crypto:mac(hmac, DigestType, Secret, Message). generate_hmac(DigestType) -> #sign_hmac{id = none, digest_type = DigestType, secret = crypto:strong_rand_bytes( ywt@internal@core:digest_size(DigestType))}. generate_ecdsa(Curve, DigestType) -> #'ECPrivateKey'{version = ecPrivkeyVer1, privateKey = PrivateKey, publicKey = PublicKey} = public_key:generate_key({namedCurve, Curve}), #sign_ecdsa{id = none, curve = Curve, digest_type = DigestType, public_key = PublicKey, private_key = PrivateKey}. generate_rsa(DigestType, KeyLength, Padding) -> #'RSAPrivateKey'{version = 'two-prime', modulus = N, publicExponent = E, privateExponent = D, prime1 = P, prime2 = Q, exponent1 = DP, exponent2 = DQ, coefficient = QI, otherPrimeInfos = Others} = public_key:generate_key({rsa, KeyLength, 65537}), Oth = case Others of asn1_NOVALUE -> []; _ -> lists:map(fun(#'OtherPrimeInfo'{prime = R, exponent = D@2, coefficient = T}) -> {R, D@2, T} end, Others) end, #sign_rsa_full{id = none, digest_type = DigestType, public_exponent = E, modulus = N, private_exponent = D, first_prime_factor = P, second_prime_factor = Q, first_factor_crt_exponent = DP, second_factor_crt_exponent = DQ, first_crt_coefficient = QI, other_primes_info = Oth, padding = Padding}.