{"action":"created","comment":{"url":"https://api.github.com/repos/ethereum/go-ethereum/pulls/comments/53127833","id":53127833,"diff_hunk":"@@ -137,47 +135,69 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {\n \t\tkey.Id.String(),\n \t\tversion,\n \t}\n-\tkeyJSON, err := json.Marshal(encryptedKeyJSONV3)\n-\tif err != nil {\n-\t\treturn err\n-\t}\n-\n-\treturn writeKeyFile(key.Address, ks.keysDirPath, keyJSON)\n+\treturn json.Marshal(encryptedKeyJSONV3)\n }\n \n-func (ks keyStorePassphrase) DeleteKey(keyAddr common.Address, auth string) (err error) {\n+func (ks keyStorePassphrase) DeleteKey(keyAddr common.Address, auth string) error {\n \t// only delete if correct passphrase is given\n-\t_, _, err = decryptKeyFromFile(ks.keysDirPath, keyAddr, auth)\n-\tif err != nil {\n+\tif _, err := decryptKeyFromFile(ks.keysDirPath, keyAddr, auth); err != nil {\n \t\treturn err\n \t}\n-\n \treturn deleteKey(ks.keysDirPath, keyAddr)\n }\n \n-func decryptKeyFromFile(keysDirPath string, keyAddr common.Address, auth string) (keyBytes []byte, keyId []byte, err error) {\n+// DecryptKey decrypts a key from a json blob, returning the private key itself.\n+func DecryptKey(keyjson []byte, auth string) (*Key, error) {\n+\t// Parse the json into a simple map to fetch the key version\n \tm := make(map[string]interface{})\n-\terr = getKey(keysDirPath, keyAddr, &m)\n-\tif err != nil {\n-\t\treturn\n+\tif err := json.Unmarshal(keyjson, &m); err != nil {\n+\t\treturn nil, err\n \t}\n-\n-\tv := reflect.ValueOf(m[\"version\"])\n-\tif v.Kind() == reflect.String && v.String() == \"1\" {\n+\t// Depending on the version try to parse one way or another\n+\tvar (\n+\t\tkeyBytes, keyId []byte\n+\t\terr             error\n+\t)\n+\tif version, ok := m[\"version\"].(string); ok && version == \"1\" {\n \t\tk := new(encryptedKeyJSONV1)\n-\t\terr = getKey(keysDirPath, keyAddr, &k)\n-\t\tif err != nil {\n-\t\t\treturn\n+\t\tif err := json.Unmarshal(keyjson, k); err != nil {\n+\t\t\treturn nil, err\n \t\t}\n-\t\treturn decryptKeyV1(k, auth)\n+\t\tkeyBytes, keyId, err = decryptKeyV1(k, auth)\n \t} else {\n \t\tk := new(encryptedKeyJSONV3)\n-\t\terr = getKey(keysDirPath, keyAddr, &k)\n-\t\tif err != nil {\n-\t\t\treturn\n+\t\tif err := json.Unmarshal(keyjson, k); err != nil {\n+\t\t\treturn nil, err\n \t\t}\n-\t\treturn decryptKeyV3(k, auth)\n+\t\tkeyBytes, keyId, err = decryptKeyV3(k, auth)\n+\t}\n+\t// Handle any decryption errors and return the key\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\tkey := ToECDSA(keyBytes)\n+\treturn &Key{\n+\t\tId:         uuid.UUID(keyId),\n+\t\tAddress:    PubkeyToAddress(key.PublicKey),\n+\t\tPrivateKey: key,\n+\t}, nil\n+}\n+\n+func decryptKeyFromFile(keysDirPath string, keyAddr common.Address, auth string) (*Key, error) {\n+\t// Load the key from the keystore and decrypt its contents\n+\tkeyjson, err := getKeyFile(keysDirPath, keyAddr)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\tkey, err := DecryptKey(keyjson, auth)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\t// Make sure we're really operating on the requested key (no swap attacks)","path":"crypto/key_store_passphrase.go","position":174,"original_position":174,"commit_id":"21238ba2dcb733955c9d6cad598be574024a16b6","original_commit_id":"21238ba2dcb733955c9d6cad598be574024a16b6","user":{"login":"karalabe","id":129561,"avatar_url":"https://avatars.githubusercontent.com/u/129561?v=3","gravatar_id":"","url":"https://api.github.com/users/karalabe","html_url":"https://github.com/karalabe","followers_url":"https://api.github.com/users/karalabe/followers","following_url":"https://api.github.com/users/karalabe/following{/other_user}","gists_url":"https://api.github.com/users/karalabe/gists{/gist_id}","starred_url":"https://api.github.com/users/karalabe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/karalabe/subscriptions","organizations_url":"https://api.github.com/users/karalabe/orgs","repos_url":"https://api.github.com/users/karalabe/repos","events_url":"https://api.github.com/users/karalabe/events{/privacy}","received_events_url":"https://api.github.com/users/karalabe/received_events","type":"User","site_admin":false},"body":"That's why I mentioned \"swap attack\". You simply swap the contents of two keys. If the passwords were the same (I'm sure many users do that for smaller wallets) then geth will gladly accept the wrong key for the address.","created_at":"2016-02-17T07:14:19Z","updated_at":"2016-02-17T07:14:19Z","html_url":"https://github.com/ethereum/go-ethereum/pull/2221#discussion_r53127833","pull_request_url":"https://api.github.com/repos/ethereum/go-ethereum/pulls/2221","_links":{"self":{"href":"https://api.github.com/repos/ethereum/go-ethereum/pulls/comments/53127833"},"html":{"href":"https://github.com/ethereum/go-ethereum/pull/2221#discussion_r53127833"},"pull_request":{"href":"https://api.github.com/repos/ethereum/go-ethereum/pulls/2221"}}},"pull_request":{"url":"https://api.github.com/repos/ethereum/go-ethereum/pulls/2221","id":59558120,"html_url":"https://github.com/ethereum/go-ethereum/pull/2221","diff_url":"https://github.com/ethereum/go-ethereum/pull/2221.diff","patch_url":"https://github.com/ethereum/go-ethereum/pull/2221.patch","issue_url":"https://api.github.com/repos/ethereum/go-ethereum/issues/2221","number":2221,"state":"open","locked":false,"title":"crypto: expose key decryption method to parse a string direclty","user":{"login":"karalabe","id":129561,"avatar_url":"https://avatars.githubusercontent.com/u/129561?v=3","gravatar_id":"","url":"https://api.github.com/users/karalabe","html_url":"https://github.com/karalabe","followers_url":"https://api.github.com/users/karalabe/followers","following_url":"https://api.github.com/users/karalabe/following{/other_user}","gists_url":"https://api.github.com/users/karalabe/gists{/gist_id}","starred_url":"https://api.github.com/users/karalabe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/karalabe/subscriptions","organizations_url":"https://api.github.com/users/karalabe/orgs","repos_url":"https://api.github.com/users/karalabe/repos","events_url":"https://api.github.com/users/karalabe/events{/privacy}","received_events_url":"https://api.github.com/users/karalabe/received_events","type":"User","site_admin":false},"body":"Currently our keystore is extremely locked down functionality wise, which make it very very brittle to use. The main limitation is that key parsing and decryption is hidden away as private internals, and wrapped around with methods that only operate on flat files, and even those files need to be named very explicitly.\r\n\r\nThe issue this causes is that given a key with an unknown file name, it's impossible to import it into the current keystore, because I simply cannot request the store to parse a string content, without needing to flush it out into a file first. But flushing to a file is not enough, as the file name needs to conform to the store spec, notable to contain the address. But to get the address, I need to interpret the contents. And the circle closes up.\r\n\r\nThis PR splits this unfortunate API design up a bit, adding an extra API endpoint that can simply parse and decrypt a key given its contents, without it needing to be in the store already. This allows geth specific keys to be imported from external sources, something not possible currently.\r\n\r\n---\r\n\r\nTwo follow up commits add:\r\n\r\n - Key file content validation to ensure noone tampered with it (i.e. it really contains the said key)\r\n - Expose a key encryption API that flattens a key into a json string, without dumping it to disk too","created_at":"2016-02-16T21:35:50Z","updated_at":"2016-02-17T07:14:19Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1007cb810873cdc2000b5c4070b662d9370bc421","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/ethereum/go-ethereum/pulls/2221/commits","review_comments_url":"https://api.github.com/repos/ethereum/go-ethereum/pulls/2221/comments","review_comment_url":"https://api.github.com/repos/ethereum/go-ethereum/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ethereum/go-ethereum/issues/2221/comments","statuses_url":"https://api.github.com/repos/ethereum/go-ethereum/statuses/21238ba2dcb733955c9d6cad598be574024a16b6","head":{"label":"karalabe:expost-key-decryption","ref":"expost-key-decryption","sha":"21238ba2dcb733955c9d6cad598be574024a16b6","user":{"login":"karalabe","id":129561,"avatar_url":"https://avatars.githubusercontent.com/u/129561?v=3","gravatar_id":"","url":"https://api.github.com/users/karalabe","html_url":"https://github.com/karalabe","followers_url":"https://api.github.com/users/karalabe/followers","following_url":"https://api.github.com/users/karalabe/following{/other_user}","gists_url":"https://api.github.com/users/karalabe/gists{/gist_id}","starred_url":"https://api.github.com/users/karalabe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/karalabe/subscriptions","organizations_url":"https://api.github.com/users/karalabe/orgs","repos_url":"https://api.github.com/users/karalabe/repos","events_url":"https://api.github.com/users/karalabe/events{/privacy}","received_events_url":"https://api.github.com/users/karalabe/received_events","type":"User","site_admin":false},"repo":{"id":33668567,"name":"go-ethereum","full_name":"karalabe/go-ethereum","owner":{"login":"karalabe","id":129561,"avatar_url":"https://avatars.githubusercontent.com/u/129561?v=3","gravatar_id":"","url":"https://api.github.com/users/karalabe","html_url":"https://github.com/karalabe","followers_url":"https://api.github.com/users/karalabe/followers","following_url":"https://api.github.com/users/karalabe/following{/other_user}","gists_url":"https://api.github.com/users/karalabe/gists{/gist_id}","starred_url":"https://api.github.com/users/karalabe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/karalabe/subscriptions","organizations_url":"https://api.github.com/users/karalabe/orgs","repos_url":"https://api.github.com/users/karalabe/repos","events_url":"https://api.github.com/users/karalabe/events{/privacy}","received_events_url":"https://api.github.com/users/karalabe/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/karalabe/go-ethereum","description":"Jeffrey Wilcke's Go implementation of the Ethereum y/w paper","fork":true,"url":"https://api.github.com/repos/karalabe/go-ethereum","forks_url":"https://api.github.com/repos/karalabe/go-ethereum/forks","keys_url":"https://api.github.com/repos/karalabe/go-ethereum/keys{/key_id}","collaborators_url":"https://api.github.com/repos/karalabe/go-ethereum/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/karalabe/go-ethereum/teams","hooks_url":"https://api.github.com/repos/karalabe/go-ethereum/hooks","issue_events_url":"https://api.github.com/repos/karalabe/go-ethereum/issues/events{/number}","events_url":"https://api.github.com/repos/karalabe/go-ethereum/events","assignees_url":"https://api.github.com/repos/karalabe/go-ethereum/assignees{/user}","branches_url":"https://api.github.com/repos/karalabe/go-ethereum/branches{/branch}","tags_url":"https://api.github.com/repos/karalabe/go-ethereum/tags","blobs_url":"https://api.github.com/repos/karalabe/go-ethereum/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/karalabe/go-ethereum/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/karalabe/go-ethereum/git/refs{/sha}","trees_url":"https://api.github.com/repos/karalabe/go-ethereum/git/trees{/sha}","statuses_url":"https://api.github.com/repos/karalabe/go-ethereum/statuses/{sha}","languages_url":"https://api.github.com/repos/karalabe/go-ethereum/languages","stargazers_url":"https://api.github.com/repos/karalabe/go-ethereum/stargazers","contributors_url":"https://api.github.com/repos/karalabe/go-ethereum/contributors","subscribers_url":"https://api.github.com/repos/karalabe/go-ethereum/subscribers","subscription_url":"https://api.github.com/repos/karalabe/go-ethereum/subscription","commits_url":"https://api.github.com/repos/karalabe/go-ethereum/commits{/sha}","git_commits_url":"https://api.github.com/repos/karalabe/go-ethereum/git/commits{/sha}","comments_url":"https://api.github.com/repos/karalabe/go-ethereum/comments{/number}","issue_comment_url":"https://api.github.com/repos/karalabe/go-ethereum/issues/comments{/number}","contents_url":"https://api.github.com/repos/karalabe/go-ethereum/contents/{+path}","compare_url":"https://api.github.com/repos/karalabe/go-ethereum/compare/{base}...{head}","merges_url":"https://api.github.com/repos/karalabe/go-ethereum/merges","archive_url":"https://api.github.com/repos/karalabe/go-ethereum/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/karalabe/go-ethereum/downloads","issues_url":"https://api.github.com/repos/karalabe/go-ethereum/issues{/number}","pulls_url":"https://api.github.com/repos/karalabe/go-ethereum/pulls{/number}","milestones_url":"https://api.github.com/repos/karalabe/go-ethereum/milestones{/number}","notifications_url":"https://api.github.com/repos/karalabe/go-ethereum/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/karalabe/go-ethereum/labels{/name}","releases_url":"https://api.github.com/repos/karalabe/go-ethereum/releases{/id}","deployments_url":"https://api.github.com/repos/karalabe/go-ethereum/deployments","created_at":"2015-04-09T12:51:45Z","updated_at":"2015-04-17T13:40:48Z","pushed_at":"2016-02-16T23:16:11Z","git_url":"git://github.com/karalabe/go-ethereum.git","ssh_url":"git@github.com:karalabe/go-ethereum.git","clone_url":"https://github.com/karalabe/go-ethereum.git","svn_url":"https://github.com/karalabe/go-ethereum","homepage":"","size":52392,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"develop"}},"base":{"label":"ethereum:develop","ref":"develop","sha":"4f28c5b69d652e12adf8a88f526f459a492e159e","user":{"login":"ethereum","id":6250754,"avatar_url":"https://avatars.githubusercontent.com/u/6250754?v=3","gravatar_id":"","url":"https://api.github.com/users/ethereum","html_url":"https://github.com/ethereum","followers_url":"https://api.github.com/users/ethereum/followers","following_url":"https://api.github.com/users/ethereum/following{/other_user}","gists_url":"https://api.github.com/users/ethereum/gists{/gist_id}","starred_url":"https://api.github.com/users/ethereum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ethereum/subscriptions","organizations_url":"https://api.github.com/users/ethereum/orgs","repos_url":"https://api.github.com/users/ethereum/repos","events_url":"https://api.github.com/users/ethereum/events{/privacy}","received_events_url":"https://api.github.com/users/ethereum/received_events","type":"Organization","site_admin":false},"repo":{"id":15452919,"name":"go-ethereum","full_name":"ethereum/go-ethereum","owner":{"login":"ethereum","id":6250754,"avatar_url":"https://avatars.githubusercontent.com/u/6250754?v=3","gravatar_id":"","url":"https://api.github.com/users/ethereum","html_url":"https://github.com/ethereum","followers_url":"https://api.github.com/users/ethereum/followers","following_url":"https://api.github.com/users/ethereum/following{/other_user}","gists_url":"https://api.github.com/users/ethereum/gists{/gist_id}","starred_url":"https://api.github.com/users/ethereum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ethereum/subscriptions","organizations_url":"https://api.github.com/users/ethereum/orgs","repos_url":"https://api.github.com/users/ethereum/repos","events_url":"https://api.github.com/users/ethereum/events{/privacy}","received_events_url":"https://api.github.com/users/ethereum/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/ethereum/go-ethereum","description":"Official golang implementation of the Ethereum protocol","fork":false,"url":"https://api.github.com/repos/ethereum/go-ethereum","forks_url":"https://api.github.com/repos/ethereum/go-ethereum/forks","keys_url":"https://api.github.com/repos/ethereum/go-ethereum/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ethereum/go-ethereum/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ethereum/go-ethereum/teams","hooks_url":"https://api.github.com/repos/ethereum/go-ethereum/hooks","issue_events_url":"https://api.github.com/repos/ethereum/go-ethereum/issues/events{/number}","events_url":"https://api.github.com/repos/ethereum/go-ethereum/events","assignees_url":"https://api.github.com/repos/ethereum/go-ethereum/assignees{/user}","branches_url":"https://api.github.com/repos/ethereum/go-ethereum/branches{/branch}","tags_url":"https://api.github.com/repos/ethereum/go-ethereum/tags","blobs_url":"https://api.github.com/repos/ethereum/go-ethereum/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ethereum/go-ethereum/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ethereum/go-ethereum/git/refs{/sha}","trees_url":"https://api.github.com/repos/ethereum/go-ethereum/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ethereum/go-ethereum/statuses/{sha}","languages_url":"https://api.github.com/repos/ethereum/go-ethereum/languages","stargazers_url":"https://api.github.com/repos/ethereum/go-ethereum/stargazers","contributors_url":"https://api.github.com/repos/ethereum/go-ethereum/contributors","subscribers_url":"https://api.github.com/repos/ethereum/go-ethereum/subscribers","subscription_url":"https://api.github.com/repos/ethereum/go-ethereum/subscription","commits_url":"https://api.github.com/repos/ethereum/go-ethereum/commits{/sha}","git_commits_url":"https://api.github.com/repos/ethereum/go-ethereum/git/commits{/sha}","comments_url":"https://api.github.com/repos/ethereum/go-ethereum/comments{/number}","issue_comment_url":"https://api.github.com/repos/ethereum/go-ethereum/issues/comments{/number}","contents_url":"https://api.github.com/repos/ethereum/go-ethereum/contents/{+path}","compare_url":"https://api.github.com/repos/ethereum/go-ethereum/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ethereum/go-ethereum/merges","archive_url":"https://api.github.com/repos/ethereum/go-ethereum/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ethereum/go-ethereum/downloads","issues_url":"https://api.github.com/repos/ethereum/go-ethereum/issues{/number}","pulls_url":"https://api.github.com/repos/ethereum/go-ethereum/pulls{/number}","milestones_url":"https://api.github.com/repos/ethereum/go-ethereum/milestones{/number}","notifications_url":"https://api.github.com/repos/ethereum/go-ethereum/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ethereum/go-ethereum/labels{/name}","releases_url":"https://api.github.com/repos/ethereum/go-ethereum/releases{/id}","deployments_url":"https://api.github.com/repos/ethereum/go-ethereum/deployments","created_at":"2013-12-26T13:05:46Z","updated_at":"2016-02-17T04:12:17Z","pushed_at":"2016-02-16T23:16:12Z","git_url":"git://github.com/ethereum/go-ethereum.git","ssh_url":"git@github.com:ethereum/go-ethereum.git","clone_url":"https://github.com/ethereum/go-ethereum.git","svn_url":"https://github.com/ethereum/go-ethereum","homepage":"http://ethereum.github.io/go-ethereum/","size":67634,"stargazers_count":960,"watchers_count":960,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":332,"mirror_url":null,"open_issues_count":167,"forks":332,"open_issues":167,"watchers":960,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ethereum/go-ethereum/pulls/2221"},"html":{"href":"https://github.com/ethereum/go-ethereum/pull/2221"},"issue":{"href":"https://api.github.com/repos/ethereum/go-ethereum/issues/2221"},"comments":{"href":"https://api.github.com/repos/ethereum/go-ethereum/issues/2221/comments"},"review_comments":{"href":"https://api.github.com/repos/ethereum/go-ethereum/pulls/2221/comments"},"review_comment":{"href":"https://api.github.com/repos/ethereum/go-ethereum/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ethereum/go-ethereum/pulls/2221/commits"},"statuses":{"href":"https://api.github.com/repos/ethereum/go-ethereum/statuses/21238ba2dcb733955c9d6cad598be574024a16b6"}}}}