{"action":"created","comment":{"url":"https://api.github.com/repos/tokenio/sdk-js/pulls/comments/193932528","pull_request_review_id":127008642,"id":193932528,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE5MzkzMjUyOA==","diff_hunk":"@@ -179,10 +226,50 @@ class Crypto {\n      * Converts a key from a string to buffer.\n      *\n      * @param {string} key - base64Url encoded key\n-     * @return {Buffer} key - key in Buffer form\n+     * @return {Uint8Array} buffered key\n      */\n     static bufferKey(key) {\n         return Crypto.wrapBuffer(base64Url.toBuffer(key));\n     }\n+\n+    /**\n+     * Converts an ECDSA signature from P1363 to DER format\n+     *\n+     * @param {ArrayBuffer} sig - P1363 signature\n+     * @return {Uint8Array} DER signature\n+     * @private\n+     */\n+    static _convertSigToDER(sig) {\n+        const signature = Array.from(new Uint8Array(sig), (x) => ('00' + x.toString(16)).slice(-2)).join('');\n+        let r = signature.substr(0, signature.length / 2);\n+        let s = signature.substr(signature.length / 2);\n+        r = r.replace(/^(00)+/, '');\n+        s = s.replace(/^(00)+/, '');\n+        if ((parseInt(r, 16) & '0x80') > 0) r = `00${r}`;\n+        if ((parseInt(s, 16) & '0x80') > 0) s = `00${s}`;\n+        const rString = `02${(r.length / 2).toString(16).padStart(2, '0')}${r}`;\n+        const sString = `02${(s.length / 2).toString(16).padStart(2, '0')}${s}`;\n+        const derSig = `30${((rString.length + sString.length) / 2).toString(16).padStart(2, '0')}${rString}${sString}`;\n+        return new Uint8Array(derSig.match(/[\\da-f]{2}/gi).map((h) => parseInt(h, 16)));\n+    }\n+\n+    /**\n+     * Converts an ECDSA signature from DER to P1363 format","path":"src/security/Crypto.js","position":329,"original_position":341,"commit_id":"541a479ad057bde80e342bd442ec91ee6db0f652","original_commit_id":"867fbdd271c37b9926d890e4877f759fdc38ee84","user":{"login":"zixunjian","id":11040393,"node_id":"MDQ6VXNlcjExMDQwMzkz","avatar_url":"https://avatars2.githubusercontent.com/u/11040393?v=4","gravatar_id":"","url":"https://api.github.com/users/zixunjian","html_url":"https://github.com/zixunjian","followers_url":"https://api.github.com/users/zixunjian/followers","following_url":"https://api.github.com/users/zixunjian/following{/other_user}","gists_url":"https://api.github.com/users/zixunjian/gists{/gist_id}","starred_url":"https://api.github.com/users/zixunjian/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zixunjian/subscriptions","organizations_url":"https://api.github.com/users/zixunjian/orgs","repos_url":"https://api.github.com/users/zixunjian/repos","events_url":"https://api.github.com/users/zixunjian/events{/privacy}","received_events_url":"https://api.github.com/users/zixunjian/received_events","type":"User","site_admin":false},"body":"r and s in DER are not guaranteed to be the same length\r\nhttps://stackoverflow.com/a/39575576\r\nfirst remove the leading double zeros and then pad a 00 if the first bit is 1. ","created_at":"2018-06-08T01:33:56Z","updated_at":"2018-06-08T01:33:56Z","html_url":"https://github.com/tokenio/sdk-js/pull/114#discussion_r193932528","pull_request_url":"https://api.github.com/repos/tokenio/sdk-js/pulls/114","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/tokenio/sdk-js/pulls/comments/193932528"},"html":{"href":"https://github.com/tokenio/sdk-js/pull/114#discussion_r193932528"},"pull_request":{"href":"https://api.github.com/repos/tokenio/sdk-js/pulls/114"}},"in_reply_to_id":193607606},"pull_request":{"url":"https://api.github.com/repos/tokenio/sdk-js/pulls/114","id":193169370,"node_id":"MDExOlB1bGxSZXF1ZXN0MTkzMTY5Mzcw","html_url":"https://github.com/tokenio/sdk-js/pull/114","diff_url":"https://github.com/tokenio/sdk-js/pull/114.diff","patch_url":"https://github.com/tokenio/sdk-js/pull/114.patch","issue_url":"https://api.github.com/repos/tokenio/sdk-js/issues/114","number":114,"state":"open","locked":false,"title":"IndexedDB + WebCrypto","user":{"login":"zixunjian","id":11040393,"node_id":"MDQ6VXNlcjExMDQwMzkz","avatar_url":"https://avatars2.githubusercontent.com/u/11040393?v=4","gravatar_id":"","url":"https://api.github.com/users/zixunjian","html_url":"https://github.com/zixunjian","followers_url":"https://api.github.com/users/zixunjian/followers","following_url":"https://api.github.com/users/zixunjian/following{/other_user}","gists_url":"https://api.github.com/users/zixunjian/gists{/gist_id}","starred_url":"https://api.github.com/users/zixunjian/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zixunjian/subscriptions","organizations_url":"https://api.github.com/users/zixunjian/orgs","repos_url":"https://api.github.com/users/zixunjian/repos","events_url":"https://api.github.com/users/zixunjian/events{/privacy}","received_events_url":"https://api.github.com/users/zixunjian/received_events","type":"User","site_admin":false},"body":"In the browser, use the Web Cryptography API for key generation and signing/verification because it supports marking keys as not extractable, meaning raw data of the private key cannot be extracted from the `CryptoKey` object, this adds security. Fallback to old library for Node. (This means we use `ECDSA` algorithm for the browser and `ED25519` algorithm for Node, this is because WebCrypto lacks support for the latter).\r\n\r\nAlso in the browser, use `IndexedDB` instead of `localStorage` for key storage, because it can store JS objects. So we can store the private key in previously mentioned `CryptoKey` object format without exposing its content.","created_at":"2018-06-06T23:42:14Z","updated_at":"2018-06-08T01:33:56Z","closed_at":null,"merged_at":null,"merge_commit_sha":"cbcf7fc7c04c28d5d0504c88de632e10b21f564a","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/tokenio/sdk-js/pulls/114/commits","review_comments_url":"https://api.github.com/repos/tokenio/sdk-js/pulls/114/comments","review_comment_url":"https://api.github.com/repos/tokenio/sdk-js/pulls/comments{/number}","comments_url":"https://api.github.com/repos/tokenio/sdk-js/issues/114/comments","statuses_url":"https://api.github.com/repos/tokenio/sdk-js/statuses/541a479ad057bde80e342bd442ec91ee6db0f652","head":{"label":"tokenio:WebCrypto","ref":"WebCrypto","sha":"541a479ad057bde80e342bd442ec91ee6db0f652","user":{"login":"tokenio","id":20025232,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIwMDI1MjMy","avatar_url":"https://avatars2.githubusercontent.com/u/20025232?v=4","gravatar_id":"","url":"https://api.github.com/users/tokenio","html_url":"https://github.com/tokenio","followers_url":"https://api.github.com/users/tokenio/followers","following_url":"https://api.github.com/users/tokenio/following{/other_user}","gists_url":"https://api.github.com/users/tokenio/gists{/gist_id}","starred_url":"https://api.github.com/users/tokenio/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tokenio/subscriptions","organizations_url":"https://api.github.com/users/tokenio/orgs","repos_url":"https://api.github.com/users/tokenio/repos","events_url":"https://api.github.com/users/tokenio/events{/privacy}","received_events_url":"https://api.github.com/users/tokenio/received_events","type":"Organization","site_admin":false},"repo":{"id":99160443,"node_id":"MDEwOlJlcG9zaXRvcnk5OTE2MDQ0Mw==","name":"sdk-js","full_name":"tokenio/sdk-js","owner":{"login":"tokenio","id":20025232,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIwMDI1MjMy","avatar_url":"https://avatars2.githubusercontent.com/u/20025232?v=4","gravatar_id":"","url":"https://api.github.com/users/tokenio","html_url":"https://github.com/tokenio","followers_url":"https://api.github.com/users/tokenio/followers","following_url":"https://api.github.com/users/tokenio/following{/other_user}","gists_url":"https://api.github.com/users/tokenio/gists{/gist_id}","starred_url":"https://api.github.com/users/tokenio/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tokenio/subscriptions","organizations_url":"https://api.github.com/users/tokenio/orgs","repos_url":"https://api.github.com/users/tokenio/repos","events_url":"https://api.github.com/users/tokenio/events{/privacy}","received_events_url":"https://api.github.com/users/tokenio/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/tokenio/sdk-js","description":"Javascript (Node and Browser) SDK for interacting with the Token System","fork":false,"url":"https://api.github.com/repos/tokenio/sdk-js","forks_url":"https://api.github.com/repos/tokenio/sdk-js/forks","keys_url":"https://api.github.com/repos/tokenio/sdk-js/keys{/key_id}","collaborators_url":"https://api.github.com/repos/tokenio/sdk-js/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/tokenio/sdk-js/teams","hooks_url":"https://api.github.com/repos/tokenio/sdk-js/hooks","issue_events_url":"https://api.github.com/repos/tokenio/sdk-js/issues/events{/number}","events_url":"https://api.github.com/repos/tokenio/sdk-js/events","assignees_url":"https://api.github.com/repos/tokenio/sdk-js/assignees{/user}","branches_url":"https://api.github.com/repos/tokenio/sdk-js/branches{/branch}","tags_url":"https://api.github.com/repos/tokenio/sdk-js/tags","blobs_url":"https://api.github.com/repos/tokenio/sdk-js/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/tokenio/sdk-js/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/tokenio/sdk-js/git/refs{/sha}","trees_url":"https://api.github.com/repos/tokenio/sdk-js/git/trees{/sha}","statuses_url":"https://api.github.com/repos/tokenio/sdk-js/statuses/{sha}","languages_url":"https://api.github.com/repos/tokenio/sdk-js/languages","stargazers_url":"https://api.github.com/repos/tokenio/sdk-js/stargazers","contributors_url":"https://api.github.com/repos/tokenio/sdk-js/contributors","subscribers_url":"https://api.github.com/repos/tokenio/sdk-js/subscribers","subscription_url":"https://api.github.com/repos/tokenio/sdk-js/subscription","commits_url":"https://api.github.com/repos/tokenio/sdk-js/commits{/sha}","git_commits_url":"https://api.github.com/repos/tokenio/sdk-js/git/commits{/sha}","comments_url":"https://api.github.com/repos/tokenio/sdk-js/comments{/number}","issue_comment_url":"https://api.github.com/repos/tokenio/sdk-js/issues/comments{/number}","contents_url":"https://api.github.com/repos/tokenio/sdk-js/contents/{+path}","compare_url":"https://api.github.com/repos/tokenio/sdk-js/compare/{base}...{head}","merges_url":"https://api.github.com/repos/tokenio/sdk-js/merges","archive_url":"https://api.github.com/repos/tokenio/sdk-js/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/tokenio/sdk-js/downloads","issues_url":"https://api.github.com/repos/tokenio/sdk-js/issues{/number}","pulls_url":"https://api.github.com/repos/tokenio/sdk-js/pulls{/number}","milestones_url":"https://api.github.com/repos/tokenio/sdk-js/milestones{/number}","notifications_url":"https://api.github.com/repos/tokenio/sdk-js/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/tokenio/sdk-js/labels{/name}","releases_url":"https://api.github.com/repos/tokenio/sdk-js/releases{/id}","deployments_url":"https://api.github.com/repos/tokenio/sdk-js/deployments","created_at":"2017-08-02T21:00:10Z","updated_at":"2018-06-07T23:41:37Z","pushed_at":"2018-06-08T01:02:40Z","git_url":"git://github.com/tokenio/sdk-js.git","ssh_url":"git@github.com:tokenio/sdk-js.git","clone_url":"https://github.com/tokenio/sdk-js.git","svn_url":"https://github.com/tokenio/sdk-js","homepage":"","size":2213,"stargazers_count":2,"watchers_count":2,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":2,"license":null,"forks":0,"open_issues":2,"watchers":2,"default_branch":"master"}},"base":{"label":"tokenio:master","ref":"master","sha":"995a4662bbaab80ae556822c26a881c1a8d8e21f","user":{"login":"tokenio","id":20025232,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIwMDI1MjMy","avatar_url":"https://avatars2.githubusercontent.com/u/20025232?v=4","gravatar_id":"","url":"https://api.github.com/users/tokenio","html_url":"https://github.com/tokenio","followers_url":"https://api.github.com/users/tokenio/followers","following_url":"https://api.github.com/users/tokenio/following{/other_user}","gists_url":"https://api.github.com/users/tokenio/gists{/gist_id}","starred_url":"https://api.github.com/users/tokenio/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tokenio/subscriptions","organizations_url":"https://api.github.com/users/tokenio/orgs","repos_url":"https://api.github.com/users/tokenio/repos","events_url":"https://api.github.com/users/tokenio/events{/privacy}","received_events_url":"https://api.github.com/users/tokenio/received_events","type":"Organization","site_admin":false},"repo":{"id":99160443,"node_id":"MDEwOlJlcG9zaXRvcnk5OTE2MDQ0Mw==","name":"sdk-js","full_name":"tokenio/sdk-js","owner":{"login":"tokenio","id":20025232,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIwMDI1MjMy","avatar_url":"https://avatars2.githubusercontent.com/u/20025232?v=4","gravatar_id":"","url":"https://api.github.com/users/tokenio","html_url":"https://github.com/tokenio","followers_url":"https://api.github.com/users/tokenio/followers","following_url":"https://api.github.com/users/tokenio/following{/other_user}","gists_url":"https://api.github.com/users/tokenio/gists{/gist_id}","starred_url":"https://api.github.com/users/tokenio/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tokenio/subscriptions","organizations_url":"https://api.github.com/users/tokenio/orgs","repos_url":"https://api.github.com/users/tokenio/repos","events_url":"https://api.github.com/users/tokenio/events{/privacy}","received_events_url":"https://api.github.com/users/tokenio/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/tokenio/sdk-js","description":"Javascript (Node and Browser) SDK for interacting with the Token System","fork":false,"url":"https://api.github.com/repos/tokenio/sdk-js","forks_url":"https://api.github.com/repos/tokenio/sdk-js/forks","keys_url":"https://api.github.com/repos/tokenio/sdk-js/keys{/key_id}","collaborators_url":"https://api.github.com/repos/tokenio/sdk-js/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/tokenio/sdk-js/teams","hooks_url":"https://api.github.com/repos/tokenio/sdk-js/hooks","issue_events_url":"https://api.github.com/repos/tokenio/sdk-js/issues/events{/number}","events_url":"https://api.github.com/repos/tokenio/sdk-js/events","assignees_url":"https://api.github.com/repos/tokenio/sdk-js/assignees{/user}","branches_url":"https://api.github.com/repos/tokenio/sdk-js/branches{/branch}","tags_url":"https://api.github.com/repos/tokenio/sdk-js/tags","blobs_url":"https://api.github.com/repos/tokenio/sdk-js/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/tokenio/sdk-js/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/tokenio/sdk-js/git/refs{/sha}","trees_url":"https://api.github.com/repos/tokenio/sdk-js/git/trees{/sha}","statuses_url":"https://api.github.com/repos/tokenio/sdk-js/statuses/{sha}","languages_url":"https://api.github.com/repos/tokenio/sdk-js/languages","stargazers_url":"https://api.github.com/repos/tokenio/sdk-js/stargazers","contributors_url":"https://api.github.com/repos/tokenio/sdk-js/contributors","subscribers_url":"https://api.github.com/repos/tokenio/sdk-js/subscribers","subscription_url":"https://api.github.com/repos/tokenio/sdk-js/subscription","commits_url":"https://api.github.com/repos/tokenio/sdk-js/commits{/sha}","git_commits_url":"https://api.github.com/repos/tokenio/sdk-js/git/commits{/sha}","comments_url":"https://api.github.com/repos/tokenio/sdk-js/comments{/number}","issue_comment_url":"https://api.github.com/repos/tokenio/sdk-js/issues/comments{/number}","contents_url":"https://api.github.com/repos/tokenio/sdk-js/contents/{+path}","compare_url":"https://api.github.com/repos/tokenio/sdk-js/compare/{base}...{head}","merges_url":"https://api.github.com/repos/tokenio/sdk-js/merges","archive_url":"https://api.github.com/repos/tokenio/sdk-js/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/tokenio/sdk-js/downloads","issues_url":"https://api.github.com/repos/tokenio/sdk-js/issues{/number}","pulls_url":"https://api.github.com/repos/tokenio/sdk-js/pulls{/number}","milestones_url":"https://api.github.com/repos/tokenio/sdk-js/milestones{/number}","notifications_url":"https://api.github.com/repos/tokenio/sdk-js/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/tokenio/sdk-js/labels{/name}","releases_url":"https://api.github.com/repos/tokenio/sdk-js/releases{/id}","deployments_url":"https://api.github.com/repos/tokenio/sdk-js/deployments","created_at":"2017-08-02T21:00:10Z","updated_at":"2018-06-07T23:41:37Z","pushed_at":"2018-06-08T01:02:40Z","git_url":"git://github.com/tokenio/sdk-js.git","ssh_url":"git@github.com:tokenio/sdk-js.git","clone_url":"https://github.com/tokenio/sdk-js.git","svn_url":"https://github.com/tokenio/sdk-js","homepage":"","size":2213,"stargazers_count":2,"watchers_count":2,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":2,"license":null,"forks":0,"open_issues":2,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/tokenio/sdk-js/pulls/114"},"html":{"href":"https://github.com/tokenio/sdk-js/pull/114"},"issue":{"href":"https://api.github.com/repos/tokenio/sdk-js/issues/114"},"comments":{"href":"https://api.github.com/repos/tokenio/sdk-js/issues/114/comments"},"review_comments":{"href":"https://api.github.com/repos/tokenio/sdk-js/pulls/114/comments"},"review_comment":{"href":"https://api.github.com/repos/tokenio/sdk-js/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/tokenio/sdk-js/pulls/114/commits"},"statuses":{"href":"https://api.github.com/repos/tokenio/sdk-js/statuses/541a479ad057bde80e342bd442ec91ee6db0f652"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"zixunjian"}}