keybase / kbpgp

OpenPGP (RFC4880) Implementation in IcedCoffeeScript
https://keybase.io/kbpgp
BSD 3-Clause "New" or "Revised" License
535 stars 74 forks source link

How do I login to keybase, retrieve my private key, and then use it to decrypt a message? #106

Closed lettergram closed 8 years ago

lettergram commented 8 years ago

I recognize this is not directly related to kbpgp. However, without receiving the proper private key it is impossible to decode messages that were encrypted from keybase. Between keybase and kbpgp I have bee unable to find a solution to this problem.

The current code I am currently using is below:

/**                                                                                            
 *  Connect to get user keys                                                                   
 */
connect = function() {

// AJAX login to get private key:                                                          
// Step One: Salt  
$.ajax({
        async: true,
        type: 'GET',
        url: "https://keybase.io/_/api/1.0/getsalt.json",
        async: false,
        data: {"email_or_username": username},

        success: function(salt) {
            if(salt && salt.status && salt.status.name == "OK"){

                var scrypt = scrypt_module_factory(67108864);
                var pwh = scrypt.crypto_scrypt(scrypt.encode_utf8(user_passphrase),
                                               scrypt.encode_utf8(salt.salt),
                                               Math.pow(2,15), 8, 1, 224).slice(192, 224);

                var login_session = CryptoJS.enc.Base64.parse(salt.login_session);
                var parsed_pwh = CryptoJS.enc.Utf8.parse(pwh);
                var hmac_pwh = CryptoJS.HmacSHA512(login_session, parsed_pwh);
                hmac_pwh = CryptoJS.enc.Hex.stringify(hmac_pwh);

                var login_data = {
                    email_or_username: username,
                    csrf_token: salt.csrf_token,
                    hmac_pwh: hmac_pwh,
                    login_session: salt.login_session
                };

                // AJAX login to get private key:                                              
                // Step Two: Login                                                             
                $.ajax({
                    async: false,
                    type: 'POST',
                    url: "https://keybase.io/_/api/1.0/login.json",
                    data: login_data,
                    dataType: "json",
                    success: function(login) {

                        if(login && login.status && login.status.name == "OK"){
                            console.log("successful login");
                        }else{
                            console.log("failed login: " + login.status.name);
                        }
                    },
                     error: function (request, status, err) {
                         console.log(err + status);
                     } 
                });
            }else{
                console.log("failed salt");
            }
        },
         error: function (request, status, err) {
             console.log(err + status);
         }
     });

I receive an error: BAD_LOGIN_PASSWORD. However, I have checked and it is not incorrect. Any help anyone could give would be great.

maxtaco commented 8 years ago

this is very hard to debug, but it doesn't seem correct to treat salt.salt as utf8 in your argument to crypto_scrypt i think it should be binary data.

On Tue, Dec 1, 2015 at 4:06 PM, Austin Walters notifications@github.com wrote:

I recognize this is not directly related to kbpgp. However, without receiving the proper private key it is impossible to decode messages that were encrypted from keybase. Between keybase and kbpgp I have bee unable to find a solution to this problem.

The current code I am currently using is below:

/**

  • Connect to get user keys */ connect = function() {

// AJAX login to get private key: // Step One: Salt $.ajax({ async: true, type: 'GET', url: "https://keybase.io/_/api/1.0/getsalt.json", async: false, data: {"email_or_username": username},

    success: function(salt) {
        if(salt && salt.status && salt.status.name == "OK"){

            var scrypt = scrypt_module_factory(67108864);
            var pwh = scrypt.crypto_scrypt(scrypt.encode_utf8(user_passphrase),
                                           scrypt.encode_utf8(salt.salt),
                                           Math.pow(2,15), 8, 1, 224).slice(192, 224);

            var login_session = CryptoJS.enc.Base64.parse(salt.login_session);
            var parsed_pwh = CryptoJS.enc.Utf8.parse(pwh);
            var hmac_pwh = CryptoJS.HmacSHA512(login_session, parsed_pwh);
            hmac_pwh = CryptoJS.enc.Hex.stringify(hmac_pwh);

            var login_data = {
                email_or_username: username,
                csrf_token: salt.csrf_token,
                hmac_pwh: hmac_pwh,
                login_session: salt.login_session
            };

            // AJAX login to get private key:
            // Step Two: Login
            $.ajax({
                async: false,
                type: 'POST',
                url: "https://keybase.io/_/api/1.0/login.json",
                data: login_data,
                dataType: "json",
                success: function(login) {

                    if(login && login.status && login.status.name == "OK"){
                        console.log("successful login");
                    }else{
                        console.log("failed login: " + login.status.name);
                    }
                },
                 error: function (request, status, err) {
                     console.log(err + status);
                 }
            });
        }else{
            console.log("failed salt");
        }
    },
     error: function (request, status, err) {
         console.log(err + status);
     }
 });

I receive an error: BAD_LOGIN_PASSWORD. However, I have checked and it is not incorrect. Any help anyone could give would be great.

— Reply to this email directly or view it on GitHub https://github.com/keybase/kbpgp/issues/106.

lettergram commented 8 years ago

@maxtaco There is a similar issue on keybase-issues:

https://github.com/keybase/keybase-issues/issues/1500

In which scrypt.encode_utf8 was also used.

From the js-scrypt we are both using:

The library enforces a strict distinction between strings and binary data. Binary data is represented using instances of Uint8Array.

scrypt.to_hex(Uint8Array) → String

Returns a lower-case hexadecimal representation of the given binary data.

scrypt.encode_utf8(String) → Uint8Array

Returns the binary equivalent of the argument, encoded using UTF-8.

I believe this is correct, I also found a function which converts hex2bin and it also fails:

function hex2bin(hex) {
    var bytes = [], str;
    for(var i=0; i< hex.length-1; i+=2)
        bytes.push(parseInt(hex.substr(i, 2), 16));
    return String.fromCharCode.apply(String, bytes);
}

This may indeed be the issue, but I have absolutely no idea how to check it.

maxtaco commented 8 years ago

If you were using node.js buffers, you'd do this new Buffer(salt.salt, "hex"). So take the salt from the server, decode hex into binary, and then pass the Uint8Array buffer into scrypt

lettergram commented 8 years ago

Duplicate, found a solution with issue #105