1 local crypto = require "util.crypto"; |
1 local crypto = require "util.crypto"; |
2 local json = require "util.json"; |
2 local json = require "util.json"; |
|
3 local hashes = require "util.hashes"; |
3 local base64_encode = require "util.encodings".base64.encode; |
4 local base64_encode = require "util.encodings".base64.encode; |
4 local base64_decode = require "util.encodings".base64.decode; |
5 local base64_decode = require "util.encodings".base64.decode; |
5 local secure_equals = require "util.hashes".equals; |
6 local secure_equals = require "util.hashes".equals; |
6 local bit = require "util.bitcompat"; |
7 local bit = require "util.bitcompat"; |
|
8 local hex = require "util.hex"; |
|
9 local rand = require "util.random"; |
7 local s_pack = require "util.struct".pack; |
10 local s_pack = require "util.struct".pack; |
8 |
11 |
9 local s_gsub = string.gsub; |
12 local s_gsub = string.gsub; |
10 |
13 |
11 local v4_public = {}; |
14 local v4_public = {}; |
112 |
115 |
113 function v4_public.new_verifier(public_key_pem, options) |
116 function v4_public.new_verifier(public_key_pem, options) |
114 return (select(2, v4_public.init(nil, public_key_pem, options))); |
117 return (select(2, v4_public.init(nil, public_key_pem, options))); |
115 end |
118 end |
116 |
119 |
|
120 local v3_local = { _key_mt = {} }; |
|
121 |
|
122 local function v3_local_derive_keys(k, n) |
|
123 local tmp = hashes.hkdf_hmac_sha384(48, k, nil, "paseto-encryption-key"..n); |
|
124 local Ek = tmp:sub(1, 32); |
|
125 local n2 = tmp:sub(33); |
|
126 local Ak = hashes.hkdf_hmac_sha384(48, k, nil, "paseto-auth-key-for-aead"..n); |
|
127 return Ek, Ak, n2; |
|
128 end |
|
129 |
|
130 function v3_local.encrypt(m, k, f, i) |
|
131 assert(#k == 32) |
|
132 if type(m) ~= "table" then |
|
133 return nil, "PASETO payloads must be a table"; |
|
134 end |
|
135 m = json.encode(m); |
|
136 local h = "v3.local."; |
|
137 local n = rand.bytes(32); |
|
138 local Ek, Ak, n2 = v3_local_derive_keys(k, n); |
|
139 |
|
140 local c = crypto.aes_256_ctr_encrypt(Ek, n2, m); |
|
141 local m2 = pae({ h, n, c, f or "", i or "" }); |
|
142 local t = hashes.hmac_sha384(Ak, m2); |
|
143 |
|
144 if not f or f == "" then |
|
145 return h..b64url(n..c..t); |
|
146 else |
|
147 return h..b64url(n..c..t).."."..b64url(f); |
|
148 end |
|
149 end |
|
150 |
|
151 function v3_local.decrypt(tok, k, expected_f, i) |
|
152 assert(#k == 32) |
|
153 |
|
154 local h, sm, f = tok:match("^(v3%.local%.)([^%.]+)%.?(.*)$"); |
|
155 if not h then |
|
156 return nil, "invalid-token-format"; |
|
157 end |
|
158 f = f and unb64url(f) or nil; |
|
159 if expected_f then |
|
160 if not f or not secure_equals(expected_f, f) then |
|
161 return nil, "invalid-footer"; |
|
162 end |
|
163 end |
|
164 local m = unb64url(sm); |
|
165 if not m or #m <= 80 then |
|
166 return nil, "invalid-token-format"; |
|
167 end |
|
168 local n, c, t = m:sub(1, 32), m:sub(33, -49), m:sub(-48); |
|
169 local Ek, Ak, n2 = v3_local_derive_keys(k, n); |
|
170 local preAuth = pae({ h, n, c, f or "", i or "" }); |
|
171 local t2 = hashes.hmac_sha384(Ak, preAuth); |
|
172 if not secure_equals(t, t2) then |
|
173 return nil, "invalid-token"; |
|
174 end |
|
175 local m2 = crypto.aes_256_ctr_decrypt(Ek, n2, c); |
|
176 if not m2 then |
|
177 return nil, "invalid-token"; |
|
178 end |
|
179 |
|
180 local payload, err = json.decode(m2); |
|
181 if err ~= nil or type(payload) ~= "table" then |
|
182 return nil, "json-decode-error"; |
|
183 end |
|
184 return payload; |
|
185 end |
|
186 |
|
187 function v3_local.new_key() |
|
188 return "secret-token:paseto.v3.local:"..hex.encode(rand.bytes(32)); |
|
189 end |
|
190 |
|
191 function v3_local.init(key, options) |
|
192 local encoded_key = key:match("^secret%-token:paseto%.v3%.local:(%x+)$"); |
|
193 if not encoded_key or #encoded_key ~= 64 then |
|
194 return error("invalid key for v3.local"); |
|
195 end |
|
196 local raw_key = hex.decode(encoded_key); |
|
197 local default_footer = options and options.default_footer; |
|
198 local default_assertion = options and options.default_implicit_assertion; |
|
199 return function (token, token_footer, token_assertion) |
|
200 return v3_local.encrypt(token, raw_key, token_footer or default_footer, token_assertion or default_assertion); |
|
201 end, function (token, token_footer, token_assertion) |
|
202 return v3_local.decrypt(token, raw_key, token_footer or default_footer, token_assertion or default_assertion); |
|
203 end; |
|
204 end |
|
205 |
|
206 function v3_local.new_signer(key, options) |
|
207 return (v3_local.init(key, options)); |
|
208 end |
|
209 |
|
210 function v3_local.new_verifier(key, options) |
|
211 return (select(2, v3_local.init(key, options))); |
|
212 end |
|
213 |
117 return { |
214 return { |
118 pae = pae; |
215 pae = pae; |
|
216 v3_local = v3_local; |
119 v4_public = v4_public; |
217 v4_public = v4_public; |
120 }; |
218 }; |