{"action":"created","comment":{"url":"https://api.github.com/repos/nodejs/node/pulls/comments/173844886","pull_request_review_id":103100745,"id":173844886,"diff_hunk":"@@ -3190,16 +3201,102 @@ void CipherBase::InitIv(const FunctionCallbackInfo<Value>& args) {\n     iv_buf = Buffer::Data(args[2]);\n     iv_len = Buffer::Length(args[2]);\n   }\n-  cipher->InitIv(*cipher_type, key_buf, key_len, iv_buf, iv_len);\n+  CHECK(args[3]->IsInt32());\n+  // Don't assign to cipher->auth_tag_len_ directly; the value might not\n+  // represent a valid length at this point.\n+  int auth_tag_len = args[3]->Int32Value();\n+\n+  cipher->InitIv(*cipher_type, key_buf, key_len, iv_buf, iv_len, auth_tag_len);\n+}\n+\n+\n+bool CipherBase::InitAuthenticated(const char *cipher_type, int iv_len,\n+                                   int auth_tag_len) {\n+  CHECK(IsAuthenticatedMode());\n+\n+  // TODO(tniessen) Use EVP_CTRL_AEAD_SET_IVLEN when migrating to OpenSSL 1.1.0\n+  static_assert(EVP_CTRL_CCM_SET_IVLEN == EVP_CTRL_GCM_SET_IVLEN,\n+                \"OpenSSL constants differ between GCM and CCM\");\n+  if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_IVLEN, iv_len, nullptr)) {\n+    env()->ThrowError(\"Invalid IV length\");\n+    return false;\n+  }\n+\n+  if (EVP_CIPHER_CTX_mode(ctx_) == EVP_CIPH_CCM_MODE) {\n+    if (auth_tag_len < 0) {\n+      char msg[128];\n+      snprintf(msg, sizeof(msg), \"authTagLength required for %s\", cipher_type);\n+      env()->ThrowError(msg);\n+      return false;\n+    }\n+\n+#ifdef NODE_FIPS_MODE\n+    // TODO(tniessen) Support CCM decryption in FIPS mode\n+    if (kind_ == kDecipher && FIPS_mode()) {\n+      env()->ThrowError(\"CCM decryption not supported in FIPS mode\");\n+      return false;\n+    }\n+#endif\n+\n+    if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_CCM_SET_TAG, auth_tag_len,\n+        nullptr)) {\n+      env()->ThrowError(\"Invalid authentication tag length\");\n+      return false;\n+    }\n+\n+    // When decrypting in CCM mode, this field will be set in setAuthTag().\n+    if (kind_ == kCipher)\n+      auth_tag_len_ = auth_tag_len;\n+\n+    // The message length is restricted to 2 ^ (15 - iv_len) - 1 bytes.\n+    CHECK(iv_len >= 7 && iv_len <= 13);\n+    switch (iv_len) {\n+    case 13:\n+    case 12:\n+#if INT_MAX >= 4294967295\n+    case 11:\n+#endif\n+#if INT_MAX >= 1099511627775\n+    case 10:\n+#endif\n+#if INT_MAX >= 281474976710655\n+    case 9:\n+#endif\n+#if INT_MAX >= 72057594037927935\n+    case 8:\n+#endif\n+#if INT_MAX >= 18446744073709551615\n+    case 7:\n+#endif","path":"src/node_crypto.cc","position":167,"original_position":167,"commit_id":"35e92f31f2eb6da76e64a45b8b7692946de42333","original_commit_id":"35e92f31f2eb6da76e64a45b8b7692946de42333","user":{"login":"shigeki","id":782880,"avatar_url":"https://avatars1.githubusercontent.com/u/782880?v=4","gravatar_id":"","url":"https://api.github.com/users/shigeki","html_url":"https://github.com/shigeki","followers_url":"https://api.github.com/users/shigeki/followers","following_url":"https://api.github.com/users/shigeki/following{/other_user}","gists_url":"https://api.github.com/users/shigeki/gists{/gist_id}","starred_url":"https://api.github.com/users/shigeki/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shigeki/subscriptions","organizations_url":"https://api.github.com/users/shigeki/orgs","repos_url":"https://api.github.com/users/shigeki/repos","events_url":"https://api.github.com/users/shigeki/events{/privacy}","received_events_url":"https://api.github.com/users/shigeki/received_events","type":"User","site_admin":false},"body":"> Apart from that, does this change match your expectations?\r\n\r\nYes. I built this in my local machine and tests work fine. ","created_at":"2018-03-12T15:46:37Z","updated_at":"2018-03-12T15:46:37Z","html_url":"https://github.com/nodejs/node/pull/18138#discussion_r173844886","pull_request_url":"https://api.github.com/repos/nodejs/node/pulls/18138","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/nodejs/node/pulls/comments/173844886"},"html":{"href":"https://github.com/nodejs/node/pull/18138#discussion_r173844886"},"pull_request":{"href":"https://api.github.com/repos/nodejs/node/pulls/18138"}},"in_reply_to_id":173825175},"pull_request":{"url":"https://api.github.com/repos/nodejs/node/pulls/18138","id":162806970,"html_url":"https://github.com/nodejs/node/pull/18138","diff_url":"https://github.com/nodejs/node/pull/18138.diff","patch_url":"https://github.com/nodejs/node/pull/18138.patch","issue_url":"https://api.github.com/repos/nodejs/node/issues/18138","number":18138,"state":"open","locked":false,"title":"crypto: add support for AES-CCM","user":{"login":"tniessen","id":3109072,"avatar_url":"https://avatars3.githubusercontent.com/u/3109072?v=4","gravatar_id":"","url":"https://api.github.com/users/tniessen","html_url":"https://github.com/tniessen","followers_url":"https://api.github.com/users/tniessen/followers","following_url":"https://api.github.com/users/tniessen/following{/other_user}","gists_url":"https://api.github.com/users/tniessen/gists{/gist_id}","starred_url":"https://api.github.com/users/tniessen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tniessen/subscriptions","organizations_url":"https://api.github.com/users/tniessen/orgs","repos_url":"https://api.github.com/users/tniessen/repos","events_url":"https://api.github.com/users/tniessen/events{/privacy}","received_events_url":"https://api.github.com/users/tniessen/received_events","type":"User","site_admin":false},"body":"# CCM (\"Counter with Cipher Block Chaining-Message Authentication Code\")\r\n\r\nOpenSSL currently supports two AEAD algorithms, GCM and CCM. While node has supported GCM for years, CCM is a bit more difficult to implement and use.\r\n\r\nCurrently, this PR implements an API similar to what was proposed by @brycekahle in https://github.com/nodejs/node/issues/2383:\r\n\r\n- `createCipher`, `createDecipher`, `createCipheriv` and `createDecipheriv` accept an option `authTagLength`. While the tag length is not relevant for GCM, it is for CCM. (And yes, using CCM with `createCipher` / `createDecipher` is inherently insecure.)\r\n- `setAAD` accepts additional `options` as an optional second argument. The only currently recognized option is `plaintextLength`, which specifies the length of the plaintext / ciphertext in bytes.\r\n\r\nThere are some critical aspects:\r\n\r\n- The current implementation always requires the `authTagLength` option when using CCM. Not providing this option causes an error to be thrown by `create(De|C)ipher(iv)?`.\r\n- Similarly, the current implementation requires the `plaintextLength` option when using CCM if and only if AAD is provided. The explanation is simple, the length of the plaintext is encoded into the first block of the cipher, and thus must be available before performing an update (and before encoding the AAD).\r\n- `update()` can only be called once. Again, the reason is very simple, CCM operates in what is sometimes called a \"packet\" or \"offline mode\", meaning that all data is processed at once.\r\n- It seems like OpenSSL does not support CCM decryption without the authentication tag.\r\n\r\nSome of these points can be relaxed:\r\n\r\n- By providing a default value for the `authTagLength` option, we could simplify the migration to this \"new\" AEAD. We could stick with the default value used within OpenSSL (12 bytes) or upgrade to 16 bytes (as e.g. [pycryptodome](http://pycryptodome.readthedocs.io/en/latest/src/cipher/aes.html) does).\r\n- By caching the data passed to `setAAD` until `update` is called, we take away the need to specify the `plaintextLength`. All data still needs to be passed to `update` in a single call.\r\n\r\nWe should discuss both, but it should be possible to add these features later on if they turn out to be good ideas (as long as they don't break anything). Aside from that, I am always happy about feedback and suggestions!\r\n\r\n<!--\r\nThank you for your pull request. Please provide a description above and review\r\nthe requirements below.\r\n\r\nBug fixes and new features should include tests and possibly benchmarks.\r\n\r\nContributors guide: https://github.com/nodejs/node/blob/master/CONTRIBUTING.md\r\n-->\r\n\r\n##### Checklist\r\n<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->\r\n\r\n- [x] `make -j4 test` (UNIX), or `vcbuild test` (Windows) passes\r\n- [x] tests and/or benchmarks are included\r\n- [x] documentation is changed or added\r\n- [x] commit message follows [commit guidelines](https://github.com/nodejs/node/blob/master/CONTRIBUTING.md#commit-message-guidelines)\r\n\r\n##### Affected core subsystem(s)\r\n<!-- Provide affected core subsystem(s) (like doc, cluster, crypto, etc). -->\r\ncrypto","created_at":"2018-01-14T02:31:36Z","updated_at":"2018-03-12T15:46:37Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a7755356281036e52bb7dffd6513f6a9ae1d5e9f","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":155267502,"url":"https://api.github.com/repos/nodejs/node/labels/C++","name":"C++","color":"e11d21","default":false},{"id":155267357,"url":"https://api.github.com/repos/nodejs/node/labels/crypto","name":"crypto","color":"009800","default":false},{"id":281232761,"url":"https://api.github.com/repos/nodejs/node/labels/lib%20/%20src","name":"lib / src","color":"fad8c7","default":false},{"id":491152610,"url":"https://api.github.com/repos/nodejs/node/labels/notable-change","name":"notable-change","color":"f9d0c4","default":false},{"id":169485514,"url":"https://api.github.com/repos/nodejs/node/labels/semver-major","name":"semver-major","color":"fbca04","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/nodejs/node/pulls/18138/commits","review_comments_url":"https://api.github.com/repos/nodejs/node/pulls/18138/comments","review_comment_url":"https://api.github.com/repos/nodejs/node/pulls/comments{/number}","comments_url":"https://api.github.com/repos/nodejs/node/issues/18138/comments","statuses_url":"https://api.github.com/repos/nodejs/node/statuses/35e92f31f2eb6da76e64a45b8b7692946de42333","head":{"label":"tniessen:ccm-is-still-weird","ref":"ccm-is-still-weird","sha":"35e92f31f2eb6da76e64a45b8b7692946de42333","user":{"login":"tniessen","id":3109072,"avatar_url":"https://avatars3.githubusercontent.com/u/3109072?v=4","gravatar_id":"","url":"https://api.github.com/users/tniessen","html_url":"https://github.com/tniessen","followers_url":"https://api.github.com/users/tniessen/followers","following_url":"https://api.github.com/users/tniessen/following{/other_user}","gists_url":"https://api.github.com/users/tniessen/gists{/gist_id}","starred_url":"https://api.github.com/users/tniessen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tniessen/subscriptions","organizations_url":"https://api.github.com/users/tniessen/orgs","repos_url":"https://api.github.com/users/tniessen/repos","events_url":"https://api.github.com/users/tniessen/events{/privacy}","received_events_url":"https://api.github.com/users/tniessen/received_events","type":"User","site_admin":false},"repo":{"id":82696757,"name":"node","full_name":"tniessen/node","owner":{"login":"tniessen","id":3109072,"avatar_url":"https://avatars3.githubusercontent.com/u/3109072?v=4","gravatar_id":"","url":"https://api.github.com/users/tniessen","html_url":"https://github.com/tniessen","followers_url":"https://api.github.com/users/tniessen/followers","following_url":"https://api.github.com/users/tniessen/following{/other_user}","gists_url":"https://api.github.com/users/tniessen/gists{/gist_id}","starred_url":"https://api.github.com/users/tniessen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tniessen/subscriptions","organizations_url":"https://api.github.com/users/tniessen/orgs","repos_url":"https://api.github.com/users/tniessen/repos","events_url":"https://api.github.com/users/tniessen/events{/privacy}","received_events_url":"https://api.github.com/users/tniessen/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/tniessen/node","description":"Node.js JavaScript runtime :sparkles::turtle::rocket::sparkles:","fork":true,"url":"https://api.github.com/repos/tniessen/node","forks_url":"https://api.github.com/repos/tniessen/node/forks","keys_url":"https://api.github.com/repos/tniessen/node/keys{/key_id}","collaborators_url":"https://api.github.com/repos/tniessen/node/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/tniessen/node/teams","hooks_url":"https://api.github.com/repos/tniessen/node/hooks","issue_events_url":"https://api.github.com/repos/tniessen/node/issues/events{/number}","events_url":"https://api.github.com/repos/tniessen/node/events","assignees_url":"https://api.github.com/repos/tniessen/node/assignees{/user}","branches_url":"https://api.github.com/repos/tniessen/node/branches{/branch}","tags_url":"https://api.github.com/repos/tniessen/node/tags","blobs_url":"https://api.github.com/repos/tniessen/node/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/tniessen/node/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/tniessen/node/git/refs{/sha}","trees_url":"https://api.github.com/repos/tniessen/node/git/trees{/sha}","statuses_url":"https://api.github.com/repos/tniessen/node/statuses/{sha}","languages_url":"https://api.github.com/repos/tniessen/node/languages","stargazers_url":"https://api.github.com/repos/tniessen/node/stargazers","contributors_url":"https://api.github.com/repos/tniessen/node/contributors","subscribers_url":"https://api.github.com/repos/tniessen/node/subscribers","subscription_url":"https://api.github.com/repos/tniessen/node/subscription","commits_url":"https://api.github.com/repos/tniessen/node/commits{/sha}","git_commits_url":"https://api.github.com/repos/tniessen/node/git/commits{/sha}","comments_url":"https://api.github.com/repos/tniessen/node/comments{/number}","issue_comment_url":"https://api.github.com/repos/tniessen/node/issues/comments{/number}","contents_url":"https://api.github.com/repos/tniessen/node/contents/{+path}","compare_url":"https://api.github.com/repos/tniessen/node/compare/{base}...{head}","merges_url":"https://api.github.com/repos/tniessen/node/merges","archive_url":"https://api.github.com/repos/tniessen/node/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/tniessen/node/downloads","issues_url":"https://api.github.com/repos/tniessen/node/issues{/number}","pulls_url":"https://api.github.com/repos/tniessen/node/pulls{/number}","milestones_url":"https://api.github.com/repos/tniessen/node/milestones{/number}","notifications_url":"https://api.github.com/repos/tniessen/node/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/tniessen/node/labels{/name}","releases_url":"https://api.github.com/repos/tniessen/node/releases{/id}","deployments_url":"https://api.github.com/repos/tniessen/node/deployments","created_at":"2017-02-21T15:39:16Z","updated_at":"2018-01-21T15:17:51Z","pushed_at":"2018-03-09T11:56:17Z","git_url":"git://github.com/tniessen/node.git","ssh_url":"git@github.com:tniessen/node.git","clone_url":"https://github.com/tniessen/node.git","svn_url":"https://github.com/tniessen/node","homepage":"https://nodejs.org","size":353678,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"nodejs:master","ref":"master","sha":"2b3f46c98946889dfd4c0ac9283c2df1ae8be45e","user":{"login":"nodejs","id":9950313,"avatar_url":"https://avatars3.githubusercontent.com/u/9950313?v=4","gravatar_id":"","url":"https://api.github.com/users/nodejs","html_url":"https://github.com/nodejs","followers_url":"https://api.github.com/users/nodejs/followers","following_url":"https://api.github.com/users/nodejs/following{/other_user}","gists_url":"https://api.github.com/users/nodejs/gists{/gist_id}","starred_url":"https://api.github.com/users/nodejs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nodejs/subscriptions","organizations_url":"https://api.github.com/users/nodejs/orgs","repos_url":"https://api.github.com/users/nodejs/repos","events_url":"https://api.github.com/users/nodejs/events{/privacy}","received_events_url":"https://api.github.com/users/nodejs/received_events","type":"Organization","site_admin":false},"repo":{"id":27193779,"name":"node","full_name":"nodejs/node","owner":{"login":"nodejs","id":9950313,"avatar_url":"https://avatars3.githubusercontent.com/u/9950313?v=4","gravatar_id":"","url":"https://api.github.com/users/nodejs","html_url":"https://github.com/nodejs","followers_url":"https://api.github.com/users/nodejs/followers","following_url":"https://api.github.com/users/nodejs/following{/other_user}","gists_url":"https://api.github.com/users/nodejs/gists{/gist_id}","starred_url":"https://api.github.com/users/nodejs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nodejs/subscriptions","organizations_url":"https://api.github.com/users/nodejs/orgs","repos_url":"https://api.github.com/users/nodejs/repos","events_url":"https://api.github.com/users/nodejs/events{/privacy}","received_events_url":"https://api.github.com/users/nodejs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/nodejs/node","description":"Node.js JavaScript runtime :sparkles::turtle::rocket::sparkles:","fork":false,"url":"https://api.github.com/repos/nodejs/node","forks_url":"https://api.github.com/repos/nodejs/node/forks","keys_url":"https://api.github.com/repos/nodejs/node/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nodejs/node/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nodejs/node/teams","hooks_url":"https://api.github.com/repos/nodejs/node/hooks","issue_events_url":"https://api.github.com/repos/nodejs/node/issues/events{/number}","events_url":"https://api.github.com/repos/nodejs/node/events","assignees_url":"https://api.github.com/repos/nodejs/node/assignees{/user}","branches_url":"https://api.github.com/repos/nodejs/node/branches{/branch}","tags_url":"https://api.github.com/repos/nodejs/node/tags","blobs_url":"https://api.github.com/repos/nodejs/node/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nodejs/node/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nodejs/node/git/refs{/sha}","trees_url":"https://api.github.com/repos/nodejs/node/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nodejs/node/statuses/{sha}","languages_url":"https://api.github.com/repos/nodejs/node/languages","stargazers_url":"https://api.github.com/repos/nodejs/node/stargazers","contributors_url":"https://api.github.com/repos/nodejs/node/contributors","subscribers_url":"https://api.github.com/repos/nodejs/node/subscribers","subscription_url":"https://api.github.com/repos/nodejs/node/subscription","commits_url":"https://api.github.com/repos/nodejs/node/commits{/sha}","git_commits_url":"https://api.github.com/repos/nodejs/node/git/commits{/sha}","comments_url":"https://api.github.com/repos/nodejs/node/comments{/number}","issue_comment_url":"https://api.github.com/repos/nodejs/node/issues/comments{/number}","contents_url":"https://api.github.com/repos/nodejs/node/contents/{+path}","compare_url":"https://api.github.com/repos/nodejs/node/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nodejs/node/merges","archive_url":"https://api.github.com/repos/nodejs/node/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nodejs/node/downloads","issues_url":"https://api.github.com/repos/nodejs/node/issues{/number}","pulls_url":"https://api.github.com/repos/nodejs/node/pulls{/number}","milestones_url":"https://api.github.com/repos/nodejs/node/milestones{/number}","notifications_url":"https://api.github.com/repos/nodejs/node/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nodejs/node/labels{/name}","releases_url":"https://api.github.com/repos/nodejs/node/releases{/id}","deployments_url":"https://api.github.com/repos/nodejs/node/deployments","created_at":"2014-11-26T19:57:11Z","updated_at":"2018-03-12T14:56:57Z","pushed_at":"2018-03-12T15:45:35Z","git_url":"git://github.com/nodejs/node.git","ssh_url":"git@github.com:nodejs/node.git","clone_url":"https://github.com/nodejs/node.git","svn_url":"https://github.com/nodejs/node","homepage":"https://nodejs.org","size":356754,"stargazers_count":46330,"watchers_count":46330,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":9709,"mirror_url":null,"archived":false,"open_issues_count":837,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":9709,"open_issues":837,"watchers":46330,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/nodejs/node/pulls/18138"},"html":{"href":"https://github.com/nodejs/node/pull/18138"},"issue":{"href":"https://api.github.com/repos/nodejs/node/issues/18138"},"comments":{"href":"https://api.github.com/repos/nodejs/node/issues/18138/comments"},"review_comments":{"href":"https://api.github.com/repos/nodejs/node/pulls/18138/comments"},"review_comment":{"href":"https://api.github.com/repos/nodejs/node/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/nodejs/node/pulls/18138/commits"},"statuses":{"href":"https://api.github.com/repos/nodejs/node/statuses/35e92f31f2eb6da76e64a45b8b7692946de42333"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"shigeki"}}