grempe / sirp

Secure (interoperable) Remote Password Auth (SRP-6a)
https://sirp-demo.herokuapp.com/index.html
Other
29 stars 12 forks source link

Amazon Cognito compatibility? #6

Closed nerdinand closed 5 years ago

nerdinand commented 6 years ago

I'm trying to use this library for authentication vs. Amazon Cognito.

Here's the code I've been trying to get to work:

          srp_client = SIRP::Client.new(3072)
          srp_a = srp_client.start_authentication
          client = Aws::CognitoIdentityProvider::Client.new

          response = client.admin_initiate_auth(
            user_pool_id: ENV['AWS_COGNITO_USER_POOL_ID'],
            client_id: ENV['AWS_COGNITO_CLIENT_ID'],
            auth_flow: 'USER_SRP_AUTH',
            auth_parameters: {
              'USERNAME' => name,
              'SRP_A' => srp_a
            }
          )

          puts "srp_a (#{srp_a.length}): #{srp_a.inspect}"

          challenge_salt = response[:challenge_parameters]['SALT']
          challenge_srp_b = response[:challenge_parameters]['SRP_B']
          challenge_secret_block_b64 = response[:challenge_parameters]['SECRET_BLOCK']
          challenge_user_id_for_srp = response[:challenge_parameters]['USER_ID_FOR_SRP']

          timestamp = Time.now.utc.strftime('%a %B %-d %H:%M:%S %Z %Y')

          puts "challenge_salt (#{challenge_salt.length}): #{challenge_salt.inspect}"
          puts "challenge_srp_b (#{challenge_srp_b.length}): #{challenge_srp_b.inspect}"

          srp_m = srp_client.process_challenge(
            challenge_user_id_for_srp, password, challenge_salt, challenge_srp_b
          )

          puts "srp_m (#{srp_m.length}): #{srp_m.inspect}"
          binary_srp_m = [srp_m].pack('H*')
          puts "binary_srp_m (#{binary_srp_m.length}): #{binary_srp_m.inspect}"

          secret_block = Base64.decode64(challenge_secret_block_b64)

          buffer = ''
          buffer << ENV['AWS_COGNITO_USER_POOL_ID'].split('_')[1]
          buffer << challenge_user_id_for_srp
          buffer << secret_block
          buffer << timestamp

          puts "buffer: #{buffer.inspect}"

          signature = OpenSSL::HMAC.digest(OpenSSL::Digest.new('SHA256'), binary_srp_m, buffer)
          signature_b64 = Base64.strict_encode64(signature)

          puts "signature_b64 (#{signature_b64.length}): #{signature_b64.inspect}"

          response = client.respond_to_auth_challenge(
            client_id: ENV['AWS_COGNITO_CLIENT_ID'],
            challenge_name: 'PASSWORD_VERIFIER',
            challenge_responses: {
              'USERNAME' => challenge_user_id_for_srp,
              'PASSWORD_CLAIM_SECRET_BLOCK' => challenge_secret_block_b64,
              'PASSWORD_CLAIM_SIGNATURE' => signature_b64,
              'TIMESTAMP': timestamp
            }
          )

Unfortunately, I always get a Incorrect username or password. error from Amazon. It looks like the first step of the protocol is implemented correctly, but Amazon doesn't accept my response to the challenge. My guess is that process_challenge doesn't exactly do what it should in this case: In the reference implementation (https://github.com/aws/aws-amplify/tree/master/packages/amazon-cognito-identity-js). I get a 16 byte long number returned from the equivalent call. However using sirp, I get a 32 byte number. I'm quite lost at the moment as I'm not super proficient with crypto code...

grempe commented 5 years ago

Sorry, this library was not created or tested with AWS Cognito in mind and if it did work it would be accidental. I'd rely on tools that AWS provides for its own auth needs. Sorry for the delay in response.

timfjord commented 4 years ago

Hi @nerdinand I faced the same issue. It looks like the AWS SRP implementation is slightly different(when the group equals 3072 AWS requires g to be 2, etc) So I ended up writing my own solution - https://github.com/timsly/aws-srp