{"action":"created","issue":{"url":"https://api.github.com/repos/codahale/bcrypt-ruby/issues/109","labels_url":"https://api.github.com/repos/codahale/bcrypt-ruby/issues/109/labels{/name}","comments_url":"https://api.github.com/repos/codahale/bcrypt-ruby/issues/109/comments","events_url":"https://api.github.com/repos/codahale/bcrypt-ruby/issues/109/events","html_url":"https://github.com/codahale/bcrypt-ruby/issues/109","id":54952090,"number":109,"title":"Ruby 2.2.0 Issue with FormEncoded Parameters","user":{"login":"davestevens","id":287677,"avatar_url":"https://avatars.githubusercontent.com/u/287677?v=3","gravatar_id":"","url":"https://api.github.com/users/davestevens","html_url":"https://github.com/davestevens","followers_url":"https://api.github.com/users/davestevens/followers","following_url":"https://api.github.com/users/davestevens/following{/other_user}","gists_url":"https://api.github.com/users/davestevens/gists{/gist_id}","starred_url":"https://api.github.com/users/davestevens/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/davestevens/subscriptions","organizations_url":"https://api.github.com/users/davestevens/orgs","repos_url":"https://api.github.com/users/davestevens/repos","events_url":"https://api.github.com/users/davestevens/events{/privacy}","received_events_url":"https://api.github.com/users/davestevens/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2015-01-20T22:48:41Z","updated_at":"2015-01-20T22:56:08Z","closed_at":null,"body":"We're currently using `Devise` to perform authentication with our App. We upgraded to Ruby 2.2.0 yesterday and noticed that we are unable to log in if there are certain characters in a users password.\r\n\r\nI've been digging into the BCrypt code and the problem seems to be somewhere in the `mri` interface. `StringValuePtr(key)` within the function `bc_crypt` reports an incorrect string/length which leads to trailing characters being used within the string which BCrypt is using.\r\n\r\nAfter attempting to replicate this problem I found that it was based around the Parameters coming into our Rails app. After further digging it seems to only be an issue with FormEncoded payloads and only `url_encoded` characters cause this problem.\r\n\r\nIts as though Rails is creating a String object which allocates the space for the url encoded characters and then continues to use this same `RString` object once it is no longer a url encoded string, resulting in `StringValuePtr` returning garbage at the end of the string being passed into `crypt_ra` which then breaks BCrypt.\r\n\r\nI assume that this is more of a Ruby issue than a BCrypt, any help would be greatly appreciated!\r\n\r\nIf you need any more information / a test project setting up let me know.\r\n\r\nExample:\r\nFormData into app:\r\n`{ user: \"email@example.com\", password: \"abcd/efgh\" }`\r\nThis is passed through to Devise, `password` is passed to `valid_password?` in `/lib/devise/models/database_authenticatable.rb` which calls `hash_secret` with the password. Within Ruby `password` is a `String` and behaves exactly how it should do. It is only once it gets into the `C` code that it breaks.\r\n`strlen(StringValuePtr(key))` returns `14` and includes garbage on the end of the string.\r\n`RSTRING_LEN(key)` returns `9`.\r\n(**NB** When changed to a json payload this is no longer an issue)\r\n\r\nThis currently fixes the problem I have been seeing\r\n```c\r\nvoid terminate_string_value_ptr(VALUE key) {\r\n  long length;\r\n  char *string;\r\n\r\n  length = RSTRING_LEN(key);\r\n  string = RSTRING_PTR(key);\r\n\r\n  string[length] = '\\0';\r\n}\r\n```\r\n\r\n```c\r\nstatic VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) {\r\n...\r\n    if(NIL_P(key) || NIL_P(setting)) {\r\n      return Qnil;\r\n    }\r\n...\r\n\r\n    // Fixes RString pointer to terminal string.\r\n    terminate_string_value_ptr(key);\r\n    terminate_string_value_ptr(setting);\r\n\r\n...\r\n    value = crypt_ra(\r\n\t    NIL_P(key) ? NULL : StringValuePtr(key),\r\n\t    NIL_P(setting) ? NULL : StringValuePtr(setting),\r\n\t    &data,\r\n\t    &size);\r\n```"},"comment":{"url":"https://api.github.com/repos/codahale/bcrypt-ruby/issues/comments/70751878","html_url":"https://github.com/codahale/bcrypt-ruby/issues/109#issuecomment-70751878","issue_url":"https://api.github.com/repos/codahale/bcrypt-ruby/issues/109","id":70751878,"user":{"login":"davestevens","id":287677,"avatar_url":"https://avatars.githubusercontent.com/u/287677?v=3","gravatar_id":"","url":"https://api.github.com/users/davestevens","html_url":"https://github.com/davestevens","followers_url":"https://api.github.com/users/davestevens/followers","following_url":"https://api.github.com/users/davestevens/following{/other_user}","gists_url":"https://api.github.com/users/davestevens/gists{/gist_id}","starred_url":"https://api.github.com/users/davestevens/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/davestevens/subscriptions","organizations_url":"https://api.github.com/users/davestevens/orgs","repos_url":"https://api.github.com/users/davestevens/repos","events_url":"https://api.github.com/users/davestevens/events{/privacy}","received_events_url":"https://api.github.com/users/davestevens/received_events","type":"User","site_admin":false},"created_at":"2015-01-20T22:56:08Z","updated_at":"2015-01-20T22:56:08Z","body":"Good point, that code I put up is just something that ended up working for the example while I was working with it.\r\nIn our production code I am making a copy of the password string from the params hash and passing that though (which also fixes it as the new string has the correct length)."}}