def main():
    emailUTF8, passwordUTF8, command = sys.argv[1:4]
    assert isinstance(emailUTF8, binary_type)
    printhex("email", emailUTF8)
    printhex("password", passwordUTF8)

    k1 = pbkdf2_bin(passwordUTF8, KWE("first-PBKDF", emailUTF8),
                    20*1000, keylen=1*32, hashfunc=sha256)
    time_k1 = time.time()
    printhex("K1", k1)
    k2 = scrypt.hash(k1, KW("scrypt"), N=64*1024, r=8, p=1, buflen=1*32)
    time_k2 = time.time()
    printhex("K2", k2)
    stretchedPW = pbkdf2_bin(k2+passwordUTF8, KWE("second-PBKDF", emailUTF8),
                             20*1000, keylen=1*32, hashfunc=sha256)
    printhex("stretchedPW", stretchedPW)

    GET("__heartbeat__")

    if command == "create":
        mainKDFSalt = makeRandom()
        srpSalt = makeRandom()
    else:
        r = POST("session/auth/start",
                 {"email": #emailUTF8.encode("hex")
                  emailUTF8.encode("utf-8")
                  })
        print "auth/start", r
        srpToken = r["srpToken"]
        B = r["srp"]["B"].decode("hex")
        srpSalt = r["srp"]["s"].decode("hex")
        mainKDFSalt = r["stretch"]["salt"].decode("hex")
        # ignore stretch.rounds, srp.N_bits, srp.alg

    printhex("mainKDFSalt", mainKDFSalt)
    printhex("srpSalt", srpSalt)

    (srpPW, unwrapBKey) = split(HKDF(SKM=stretchedPW,
                                     XTS=mainKDFSalt,
                                     CTXinfo=KW("mainKDF"),
                                     dkLen=2*32))

    if command == "create":
        (srpVerifier, _, _, _, _) = mysrp.create_verifier(emailUTF8, srpPW,
                                                          srpSalt)

        r = POST("account/create",
                 {#"email": emailUTF8.encode("hex"), # TODO prefer hex
                     "email": emailUTF8.encode("utf-8"),
                  "verifier": srpVerifier.encode("hex"),
                  "salt": srpSalt.encode("hex"),
                  "params": {"srp": {"alg": "sha256", "N_bits": 2048},
                             "stretch": {"salt": mainKDFSalt.encode("hex"),
                                         "rounds": 20000}
                             },
                  })
        print r
    else:
        srpClient = mysrp.Client()
        A = srpClient.one()
        M1 = srpClient.two(B, srpSalt, emailUTF8, srpPW)
        r = POST("session/auth/finish",
                 {"srpToken": srpToken,
                  "A": A.encode("hex"),
                  "M": M1.encode("hex")})
        print "auth/finish:", r
        bundle = r["bundle"].decode("hex")
        print "bundlelen", len(bundle)

        # note: the server is not yet using the new protocol. The old one
        # returns keyFetchToken+sessionToken
        if 1: # old protocol
            x = HKDF(SKM=srpClient.get_key(),
                     dkLen=3*32,
                     XTS=None,
                     CTXinfo=KW("session/auth"))
            respHMACkey = x[0:32]
            respXORkey = x[32:]
            ct,respMAC = bundle[:-32], bundle[-32:]
            respMAC2 = HMAC(respHMACkey, ct)
            printhex("respHMACkey", respHMACkey)
            printhex("respXORkey", respXORkey)
            printhex("ct", ct)
            assert respMAC2 == respMAC, (respMAC2.encode("hex"),
                                         respMAC.encode("hex"))
            keyFetchToken, sessionToken = split(xor(respXORkey,ct))

        if 0: # new protocol
            authToken = getAuthToken(srpClient.get_key())
            x = HKDF(SKM=srpClient.get_key(),
                     dkLen=2*32,
                     XTS=None,
                     CTXinfo=KW("auth/finish"))
            respHMACkey = x[0:32]
            respXORkey = x[32:]
            ct,respMAC = bundle[:-32], bundle[-32:]
            respMAC2 = HMAC(respHMACkey, ct)
            assert respMAC2 == respMAC, (respMAC2.encode("hex"),
                                         respMAC.encode("hex"))
            authToken = xor(ct, respXORkey)
            printhex("authToken", authToken)
            keyFetchToken, sessionToken = createSession(authToken)

        printhex("keyFetchToken", keyFetchToken)
        printhex("sessionToken", sessionToken)

        kA,kB = getKeys(keyFetchToken, unwrapBKey)
        printhex("kA", kA)
        printhex("kB", kB)
Exemple #2
0
def main():
    emailUTF8, passwordUTF8, command = sys.argv[1:4]
    assert command in ("create", "login", "changepw", "destroy",
                       "forgotpw1", "forgotpw2")
    assert isinstance(emailUTF8, binary_type)
    printhex("email", emailUTF8)
    printhex("password", passwordUTF8)

    GET("__heartbeat__", versioned="")

    if command == "forgotpw1":
        r = POST("password/forgot/send_code",
                 {"email": emailUTF8.encode("hex")})
        print r
        return

    if command == "create":
        mainKDFSalt = makeRandom()
        srpSalt = makeRandom()
        PBKDF2_rounds_1 = PBKDF2_rounds_2 = 20*1000
        scrypt_N = 64*1024
        scrypt_r = 8
        scrypt_p = 1
    elif command in ("login", "changepw", "destroy"):
        r = POST("auth/start",
                 {"email": emailUTF8.encode("hex")
                  })
        print "auth/start", r
        st = r["passwordStretching"]
        assert st["type"] == "PBKDF2/scrypt/PBKDF2/v1"
        mainKDFSalt = st["salt"].decode("hex")
        PBKDF2_rounds_1 = st["PBKDF2_rounds_1"]
        PBKDF2_rounds_2 = st["PBKDF2_rounds_2"]
        scrypt_N = st["scrypt_N"]
        scrypt_r = st["scrypt_r"]
        scrypt_p = st["scrypt_p"]

        srpToken = r["srpToken"]
        srpSalt = r["srp"]["salt"].decode("hex")
        B = r["srp"]["B"].decode("hex")
    else:
        assert False

    printhex("mainKDFSalt", mainKDFSalt)
    printhex("srpSalt", srpSalt)

    # MANGLE
    mangled_email = emailUTF8.encode("hex") if MANGLE else emailUTF8
    stretchedPW = stretch(mangled_email, passwordUTF8, PBKDF2_rounds_1,
                          scrypt_N, scrypt_r, scrypt_p, PBKDF2_rounds_2)

    (srpPW, unwrapBKey) = mainKDF(stretchedPW, mainKDFSalt)
    mangled_srpPW = srpPW.encode("hex") if MANGLE else srpPW

    if command == "create":

        (srpVerifier, _, _, _, _) = mysrp.create_verifier(mangled_email,
                                                          mangled_srpPW,
                                                          srpSalt)
        r = POST("account/create",
                 {"email": emailUTF8.encode("hex"),
                  "srp": {
                      "type": "SRP-6a/SHA256/2048/v1",
                      "verifier": srpVerifier.encode("hex"),
                      "salt": srpSalt.encode("hex"),
                    },
                  "passwordStretching": {
                      "type": "PBKDF2/scrypt/PBKDF2/v1",
                      "PBKDF2_rounds_1": PBKDF2_rounds_1,
                      "scrypt_N": scrypt_N,
                      "scrypt_r": scrypt_r,
                      "scrypt_p": scrypt_p,
                      "PBKDF2_rounds_2": PBKDF2_rounds_2,
                      "salt": mainKDFSalt.encode("hex"),
                      },
                  })
        print r
    elif command in ("login", "changepw", "destroy"):
        srpClient = mysrp.Client()
        A = srpClient.one()
        M1 = srpClient.two(B, srpSalt, mangled_email, mangled_srpPW)
        r = POST("auth/finish",
                 {"srpToken": srpToken,
                  "A": A.encode("hex"),
                  "M": M1.encode("hex")})
        print "auth/finish:", r
        bundle = r["bundle"].decode("hex")
        print "bundlelen", len(bundle)

        x = HKDF(SKM=srpClient.get_key(),
                 dkLen=2*32,
                 XTS=None,
                 CTXinfo=KW("auth/finish"))
        respHMACkey = x[0:32]
        respXORkey = x[32:]
        ct,respMAC = bundle[:-32], bundle[-32:]
        respMAC2 = HMAC(respHMACkey, ct)
        assert respMAC2 == respMAC, (respMAC2.encode("hex"),
                                     respMAC.encode("hex"))
        authToken = xor(ct, respXORkey)
        printhex("authToken", authToken)
    else:
        assert False

    if command == "login":
        keyFetchToken, sessionToken = createSession(authToken)
        printhex("keyFetchToken", keyFetchToken)
        printhex("sessionToken", sessionToken)
        email_status = getEmailStatus(sessionToken)
        print "email status:", email_status
        kA,kB = getKeys(keyFetchToken, unwrapBKey)
        printhex("kA", kA)
        printhex("kB", kB)
        # TODO: exercise /certificate/sign

    if command == "changepw":
        keyFetchToken, accountResetToken = changePassword(authToken)
        printhex("keyFetchToken", keyFetchToken)
        printhex("accountResetToken", accountResetToken)
        kA,kB = getKeys(keyFetchToken, unwrapBKey)
        printhex("kA", kA)
        printhex("kB", kB)

        # stretch new password
        new_passwordUTF8 = sys.argv[4]
        new_stretchedPW = stretch(emailUTF8, new_passwordUTF8, PBKDF2_rounds_1,
                                  scrypt_N, scrypt_r, scrypt_p, PBKDF2_rounds_2)
        new_mainKDFSalt = makeRandom()
        new_srpSalt = makeRandom()
        (new_srpPW, new_unwrapBKey) = mainKDF(new_stretchedPW, new_mainKDFSalt)
        # build new srpVerifier
        (new_srpVerifier, _,_,_,_) = mysrp.create_verifier(emailUTF8,
                                                           new_srpPW,
                                                           new_srpSalt)
        assert len(new_srpVerifier) == 256, len(new_srpVerifier)
        printhex("new_srpVerifier", new_srpVerifier)
        # re-wrap kB
        new_wrap_kB = xor(kB, new_unwrapBKey)
        printhex("new_wrap_kB", new_wrap_kB)

        # submit /account/reset
        x = HKDF(SKM=accountResetToken,
                 XTS=None,
                 CTXinfo=KW("accountResetToken"),
                 dkLen=3*32)
        tokenID, reqHMACkey1, requestKey = split(x)
        plaintext = new_wrap_kB+new_srpVerifier
        print "LEN PLAIN", len(plaintext)
        y = HKDF(SKM=requestKey,
                 XTS=None,
                 CTXinfo=KW("account/reset"),
                 dkLen=32+len(plaintext))
        reqHMACkey2 = y[:32]
        reqXORkey = y[32:]
        bundle = xor(reqXORkey, plaintext)
        bundle_mac = HMAC(reqHMACkey2, bundle)
        payload = {"bundle": (bundle+bundle_mac).encode("hex"),
                   "srp": {
                       "type": "SRP-6a/SHA256/2048/v1",
                       "salt": new_srpSalt.encode("hex"),
                       },
                   "passwordStretching": {
                       "type": "PBKDF2/scrypt/PBKDF2/v1",
                       "PBKDF2_rounds_1": PBKDF2_rounds_1,
                       "scrypt_N": scrypt_N,
                       "scrypt_r": scrypt_r,
                       "scrypt_p": scrypt_p,
                       "PBKDF2_rounds_2": PBKDF2_rounds_2,
                       "salt": new_mainKDFSalt.encode("hex"),
                       },
                   }
        r = HAWK_POST("account/reset", tokenID, reqHMACkey1, payload)
        assert r == {}, r
        print "password changed"

    if command == "destroy":
        tokenID, reqHMACkey, requestKey = processAuthToken(authToken)
        r = HAWK_POST("account/destroy", tokenID, reqHMACkey, {})
        print r