Packages

The ywt package for JWT targeting erlang.

Current section

Files

Jump to
ywt_erlang src ywt_ffi.erl
Raw

src/ywt_ffi.erl

-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}},
case catch public_key:verify(Message, DigestType, DerSignature, Params) of
true ->
true;
_ ->
false
end;
verify(Message,
Signature,
#verify_rsa{digest_type = DigestType,
exponent = E,
modulus = N,
padding = Padding}) ->
PublicKey = #'RSAPublicKey'{modulus = N, publicExponent = E},
case catch public_key:verify(Message,
DigestType,
Signature,
PublicKey,
[{rsa_padding, Padding}])
of
true ->
true;
_ ->
false
end;
verify(Message, Signature, #verify_hmac{digest_type = DigestType, secret = Secret}) ->
case catch crypto:hash_equals(
crypto:mac(hmac, DigestType, Secret, Message), Signature)
of
true ->
true;
_ ->
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.)
<<R:RSSize, S:RSSize>>;
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}.