diff --git a/include/jwt/base64.hpp b/include/jwt/base64.hpp index faaad0f..552ec4c 100644 --- a/include/jwt/base64.hpp +++ b/include/jwt/base64.hpp @@ -3,10 +3,11 @@ #include #include +#include "jwt/string_view.hpp" namespace jwt { -/* +/*! * Encoding map. */ class EMap @@ -30,7 +31,8 @@ private: }; }; - +/*! + */ std::string base64_encode(const char* in, size_t len) { std::string result; @@ -120,7 +122,8 @@ private: }; }; - +/*! + */ std::string base64_decode(const char* in, size_t len) { std::string result; @@ -184,6 +187,31 @@ std::string base64_decode(const char* in, size_t len) return result; } +/*! + */ +void base64_uri_encode(char* data, size_t len) noexcept +{ + size_t i = 0; + size_t j = 0; + + for (; i < len; ++i) { + switch (data[i]) { + case '+': + data[j++] = '-'; + break; + case '/': + data[j++] = '_'; + break; + case '=': + break; + default: + data[j++] = data[i]; + }; + } + + return; +} + } // END namespace jwt diff --git a/include/jwt/impl/jwt.ipp b/include/jwt/impl/jwt.ipp index af84bd8..134142d 100644 --- a/include/jwt/impl/jwt.ipp +++ b/include/jwt/impl/jwt.ipp @@ -30,6 +30,75 @@ std::ostream& operator<< (std::ostream& os, const T& obj) return os; } +std::string jwt_signature::encode(const jwt_header& header, + const jwt_payload& payload) +{ + std::string jwt_msg; + //TODO: Optimize allocations + + sign_func_t sign_fn = get_algorithm_impl(header); + + std::string hdr_sign = header.base64_encode(); + std::string pld_sign = payload.base64_encode(); + + base64_uri_encode(&hdr_sign[0], hdr_sign.length()); + base64_uri_encode(&pld_sign[0], pld_sign.length()); + + std::string data = hdr_sign + '.' + pld_sign; + auto res = sign_fn(key_, data); + + std::string b64hash = base64_encode(res.first.c_str(), res.first.length()); + base64_uri_encode(&b64hash[0], b64hash.length()); + + jwt_msg = data + '.' + b64hash; + + return jwt_msg; +} + + +sign_func_t +jwt_signature::get_algorithm_impl(const jwt_header& hdr) const noexcept +{ + sign_func_t ret = nullptr; + + switch (hdr.algo()) { + case algorithm::HS256: + ret = HMACSign::sign; + break; + case algorithm::HS384: + ret = HMACSign::sign; + break; + case algorithm::HS512: + ret = HMACSign::sign; + break; + case algorithm::NONE: + ret = HMACSign::sign; + break; + case algorithm::RS256: + ret = PEMSign::sign; + break; + case algorithm::RS384: + ret = PEMSign::sign; + break; + case algorithm::RS512: + ret = PEMSign::sign; + break; + case algorithm::ES256: + ret = PEMSign::sign; + break; + case algorithm::ES384: + ret = PEMSign::sign; + break; + case algorithm::ES512: + ret = PEMSign::sign; + break; + default: + assert (0 && "Code not reached"); + }; + + return ret; +} + } // END namespace jwt diff --git a/include/jwt/jwt.hpp b/include/jwt/jwt.hpp index 5df200b..1d1e2cc 100644 --- a/include/jwt/jwt.hpp +++ b/include/jwt/jwt.hpp @@ -8,6 +8,7 @@ #include #include "jwt/base64.hpp" +#include "jwt/algorithm.hpp" #include "jwt/string_view.hpp" #include "jwt/detail/meta.hpp" #include "jwt/json/json.hpp" @@ -342,6 +343,37 @@ private: */ struct jwt_signature { +public: // 'tors + /// Default constructor + jwt_signature() = default; + + /*! + */ + jwt_signature(string_view key) + : key_(key.data(), key.length()) + { + } + + /// Default copy and assignment operator + jwt_signature(const jwt_signature&) = default; + jwt_signature& operator=(const jwt_signature&) = default; + + ~jwt_signature() = default; + +public: // Exposed APIs + /*! + */ + std::string encode(const jwt_header& header, + const jwt_payload& payload); + +private: // Private implementation + /*! + */ + sign_func_t get_algorithm_impl(const jwt_header& hdr) const noexcept; + +private: // Data members; + /// The key for creating the JWS + std::string key_; }; diff --git a/include/jwt/test/test_jwt_signature b/include/jwt/test/test_jwt_signature new file mode 100755 index 0000000..d4482a1 Binary files /dev/null and b/include/jwt/test/test_jwt_signature differ diff --git a/include/jwt/test/test_jwt_signature.cc b/include/jwt/test/test_jwt_signature.cc new file mode 100644 index 0000000..7a95082 --- /dev/null +++ b/include/jwt/test/test_jwt_signature.cc @@ -0,0 +1,24 @@ +#include +#include "jwt/jwt.hpp" + +void basic_sign_test() +{ + // Create header + jwt::jwt_header hdr; + hdr = jwt::jwt_header{jwt::algorithm::HS256}; + + // Create payload + jwt::jwt_payload jp; + jp.add_claim("sub", "1234567890"); + jp.add_claim("name", "John Doe"); + jp.add_claim("admin", true); + + jwt::jwt_signature sgn{"secret"}; + auto res = sgn.sign(hdr, jp); + std::cout << res << std::endl; +} + +int main() { + basic_sign_test(); + return 0; +}