Example #1
0
def test_read_armored():
    """ Make sure the modulus PGP message is read correctly
    
    ProtonMail's response is NOT a valid OpenPGP message!
    
    """
    # ProtonMail's signed modulus message is NOT a valid PGP message
    modulus = auth.read_armored(AUTH_INFO['Modulus'])
    assert modulus == 'c5fkhlTPZsqb/ujEbCVdeUaCQUhDPeVgA5dN3q2jLoQcRrif5/LLp+BosQo4fiVVzZCnGHPGIvFsGf0n/bojbiizO+OfnnuHl+FYK0Qno83FJQ7GXebF4VghRHxEyuokdo4r9QozB9FBBm0M0vcElG0qyDG5p9HP+dXvd7OzcHChPmnJCweALSu7TfUQ4R1ADFVG909XxS9V4G3YEHRo1xGSyzK41YCCG3LYEhwM5I/ygcGLOxNFmGcq63afhVd7JAi2XD0YgzsPm5sM/aAVBd6RvWiKRV8vIDCOMlbax4ZitH4dABKXzO6Tdh9Je5fZcsuYlmN3wScUg6se7QYZsA=='
    # Convert to int
    m = auth.to_bn(base64.b64decode(modulus))
    assert m.bit_length() in (2048, 2047)  # TODO: Why is it -1 ?
Example #2
0
    def _default_ClientProof(self):
        """ Computes the ClientProof from the AuthInfo """
        info = self.AuthInfo
        proofs = auth.generate_proofs(self.KeySize,
                                      b64d(auth.read_armored(info.Modulus)),
                                      self.HashedPassword,
                                      b64d(info.ServerEphemeral))

        self.ClientEphemeral = proofs['client_ephemeral']
        self.ExpectedServerProof = proofs['server_proof']

        return proofs['client_proof']
Example #3
0
def test_hashed_pwd():
    """ Make sure the hashed password matches 
    """
    modulus = base64.b64decode(auth.read_armored(AUTH_INFO['Modulus']))

    # Check salt at different stages
    salt = base64.b64decode(AUTH_INFO['Salt'])
    assert base64.b64encode(salt+'proton') == "Mc/pO/VHMVR/y3Byb3Rvbg=="
    assert '$2y$10$'+auth.bcrypt_encode_base64(salt+'proton') == "$2y$10$Ka9nM9TFKTP9w1/wZ1PtZe"

    # Make sure it's what we expect
    p = auth.hash_password(3, 'protonmail', salt, 'notused', modulus)
    assert base64.b64encode(p) == 'CFX3pYh45jr8hmODKF35o2XsCqj3ZgJT4goskAq59B4XNk6Ut5NYLl74SxOYkncQTTAG5exhgDTiIuKe6KKSh6ORJDBBXgT8WCsR9OgaD5FO9FNwRKIOxDBZqledH/lmFdzg2q56qCcLbAPY7cS0TVJax3khIGcd4eBKvoS5PA1ReoO1p7H5sZzj1xzGpuLTyG/LYruV6mXUuYTKVU+K/ZBTEktYmjDTgczJzkZsXKRD3Bx8g/5SIMkfpSndz/lRJR2rOmeJ5fSiv7esFQ8VIkSLxYOVLcb4y1U95q5luo7e79ZV4wm+IHIg1ywi5zF4SFe5i4cICI94Kzf9OxQntA=='
Example #4
0
def test_client_proofs():
    b64e, b64d = base64.b64encode, base64.b64decode
    modulus = b64d(auth.read_armored(AUTH_INFO['Modulus']))
    salt = b64d(AUTH_INFO['Salt'])
    hashed_password = auth.hash_password(3, 'protonmail', salt, 'notused', modulus)
    server_ephemeral = b64d(AUTH_INFO['ServerEphemeral'])

    assert b64e(server_ephemeral) == "6dIgR0DzZxEUM/6+IJbetYfb/O7IIlhX2Q6kKvkBN0SL1cAWGvY35O6P/x5LDsnh1HmVtMS/LcBAZW5z1c1a4O0XFGbZ5PwSXHbN4VNVnmjxCioT3B2KCj/O1kbLXYsiTPs0zPnEORPguGHy13UeRmZJw4QdiPqIkzTWLdO9k5WuOCqW2WJeLOr5Kt2Rb/GADSnJca9MWo3CkXskEptd0i24QNjKpe47nBA6Ycz10bYPaGkiQ6Mi5eFE3CfEDARkDIPW910+rH3YCMtI1oqLxEGSF9FBaKqg7F8Q07Tf5LW+/8DjYI5AUReendBKyvpcYhVEgapeYYpQIiV/gyp6ew=="
    assert b64e(auth.from_bn(2)+modulus) == "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHOX5IZUz2bKm/7oxGwlXXlGgkFIQz3lYAOXTd6toy6EHEa4n+fyy6fgaLEKOH4lVc2QpxhzxiLxbBn9J/26I24oszvjn557h5fhWCtEJ6PNxSUOxl3mxeFYIUR8RMrqJHaOK/UKMwfRQQZtDNL3BJRtKsgxuafRz/nV73ezs3BwoT5pyQsHgC0ru031EOEdQAxVRvdPV8UvVeBt2BB0aNcRkssyuNWAghty2BIcDOSP8oHBizsTRZhnKut2n4VXeyQItlw9GIM7D5ubDP2gFQXekb1oikVfLyAwjjJW2seGYrR+HQASl8zuk3YfSXuX2XLLmJZjd8EnFIOrHu0GGbA="
    multiplier = auth.hash(auth.from_bn(2)+modulus)
    assert b64e(multiplier) == "DpI3RvLj80Kbb95hfNyYyS96MHVVNaoQv2zZQLgAihr7X8B/K7qy+kI+CmqAruoODpNxovaDo65FhoO3+KC1b0G++O7Ej5o03UEZWsAQ9NJ5AB6qE0dPJnxKRWvcJzXrZ4tkjTEp0MfMUo0Bw+qOrelOp6hLaQaD67bZHoJmyenuv0ApYgdwy6Cux05Xmf47FgNcW0t1v4XNU9EyfzC9mqZkxhbQq9roVleDtTYZESkl1DrsVN95LCc6VncmeNX9bfA1O8w897GHQLP85kNZfkmFkJb2n0BYX6JqDLD/aCkT80G4P3jx8DFXQrGsvqN6VLO6x6FLf+Y2NyGNG3Q/wA=="

    multiplier = auth.from_bn(auth.mod_reduce(auth.to_bn(multiplier), auth.to_bn(modulus)))
    assert b64e(multiplier) == "m/pSv50UjXj/cPWcD7c7UOn37iwS+MSvu9WLYgpdW5beGQjgQ8fmUmLVWF9IMMW5QALKiYO9gL3YbIaP++WRARkLvQsl8R6tRWDALnzpUAW02g/ktWCJRCMpAe+XXUrG8fw4mCb2yPaKTCD18PKJGXwk33aSwTSz8eDpps6yWHlNgddfVgDwnXXzeVlGuOD7Ca4VZPsd+lV4c2NabrxUw5TS+uMX1llmO+WqohoNLZkyUnlgGcw0lL8PawCH8n2CSeh/3o4kdHZ4pRfw6aJDeWvz0i1sWuEoP3Lc2VkloaKwPsOaP2ZaJEPDy5FjQwyh4echMT7Uvb4itHVuLm0mEA=="

    g = 2
    p = auth.to_bn(modulus)
    hpw = auth.to_bn(hashed_password)
    m = auth.to_bn(multiplier)
    # Hard code for test
    client_secret = b64d("xBm+aaHCvnIHupRLuNB33xZdmb1iS1uErD8wyGaRX5IGs1gBXTbINbhJ5qTfydiy1PgVIzsXwfHG7X0MRQ0Ote7mpUE/2J6xPQ9aF09QRbixAHpZ6x+fX1vo4XpXJgBM0YVtA7RF+ln/Dm5vBiW0NQlG6+JpGyKTeUXpQiypgTZOZw0Bonvo8z/uwAlKLr3c2q+hVClK7+WcbF5UdC3ijddAtV5UIrUei9iaL91k5Dq+hxw76jJAme8w9Qz8NPxc3t0JDdw4eyqUMNwP1PIzlbvtmn6BkbTGBFOdNfQYg6oYwh93ESAnVzL1p/nrgf89ch4kohjIGDgXqnQEvVcC7g==")

    client_ephemeral = auth.from_bn(pow(g, auth.to_bn(client_secret), p))
    assert b64e(client_ephemeral) == "XTaTsmCVqIns4E8dmMNOHpGIvh0j6zXD2cFtRKpNaFNV1zgRyo1CtxwcZO1l3sSk6FqhdBpDZrafSoF4mJIlYhrI4pIxvKiTTVWH50pPDRP6pCA64sHsUgKazHGnM09u29FocjqcewN6Oe+ZIm+A8TnssDmGI80XSy1nhbbPcQCn+VeTGR7g2f3l/7AbEMKnzWg3sZ2NAuNSYQaG2Kd211ZuLgEPQzWxPS+8ePACoWYnS3bzDDi8JXEKM6aXIqcY1+WG6Y1mks7k+bLyt62YfuFnjUzygzmXx6cuaw6UHmuHnfoiObDU5qwM+/RPpvvOCQ7pqB3ufvhgpAm+YiSVdg=="

    scrambling_param = auth.hash(client_ephemeral+server_ephemeral)
    assert b64e(scrambling_param) == "rEtrIOzSKNdsdWgrNAShlFA7oj7O1nt6OaDcW0RZqeExwhT2oU72ieaRy+kMFWMXeGPWCMiaueunGX2eJX0a2mSPKkFQsgXF61xeREgrkDTs2UNKSTXMHOZ0xftbCbmp0+nA/P2nv678wpcDJoN8eWEbvBdl8j7sUOIZ9xZcTp934ff9jqCUNc0sRl8122lgIRKkzAKNyeCOsm5eD16NDpCDp1P3VOGPmhz7bGBit5SoT6NImVyi1Y49h/7T9WQ6IG+gFqihbOZjMNR7E8u2Cbj7loiMSmIPvixonPbTgQI/GkQVT3Nu8RkKMg6nvQTArz/YucS6JmRcqMMzcrq9tg=="

    subtracted = auth.to_bn(server_ephemeral) - auth.mod_reduce(pow(g, hpw, p)*m, p)
    assert b64e(auth.from_bn(subtracted)) == "lRcHTWAmTnndNWVYOOqTjN/BXB6JyQNcbHwMiteJ0/Iw50rGSoDUfc9u+ggUDqhlth7n/fAT7ZrVZdgp9VBPfyvsyYX2UsOOs3OfJ7+ZnZ1O9GCLjgOo7zaok88FIcKmnzXRdkB1DBlEdIRvrQjDAsSar/FCbugoCPC/04xBkUYkWAj05O+pdq3NFz6/6O3NF06bCw2k8PlZF3VXs/F3M/7WkY3MFqNDClNFPnJXP1f0MDP8aHbMQ6D4VypASydZepHcubrklb8kB/e+W3I5HWKqgAisMZgw+PQTb+UTFFZxRihtOD1rDuuifnHpNvZIGwVv54DLEcA2RUsg3tiNLg=="
    if subtracted < 0:
        subtracted += p
    assert b64e(auth.from_bn(subtracted)) == "lRcHTWAmTnndNWVYOOqTjN/BXB6JyQNcbHwMiteJ0/Iw50rGSoDUfc9u+ggUDqhlth7n/fAT7ZrVZdgp9VBPfyvsyYX2UsOOs3OfJ7+ZnZ1O9GCLjgOo7zaok88FIcKmnzXRdkB1DBlEdIRvrQjDAsSar/FCbugoCPC/04xBkUYkWAj05O+pdq3NFz6/6O3NF06bCw2k8PlZF3VXs/F3M/7WkY3MFqNDClNFPnJXP1f0MDP8aHbMQ6D4VypASydZepHcubrklb8kB/e+W3I5HWKqgAisMZgw+PQTb+UTFFZxRihtOD1rDuuifnHpNvZIGwVv54DLEcA2RUsg3tiNLg=="

    exponent = (auth.to_bn(scrambling_param) * hpw + auth.to_bn(client_secret))%(p-1)
    assert b64e(auth.from_bn(exponent)) == "sD+rPM/unfrYzwtTbm/sNfaEyaEzwEcTD1Kth6p7sT+0AEYZ8+A1vPrSQ7DjUqmyGlw2KCQk3mZ6iBgjkoPisHxLlZ+xgb/cEgloF8OkBNv/oOckk2wwNW1j2SNyja5H1NBzIQZ+yB2LJdcZVmdy27kbEMGHqYxJ40HAZTNPHhBmcZC9CD/pXQSdvAE2qFTi43xJF3fDWJARTtNDyLUxp4RG33ikYGsNFVML1dUMVhFYSIc914TSZtcITSC1uD1GMAMUMHRGEn8n2lgBXpRBQTNmAVSANnKeJoocIgV1FCGCN1n42YhcGS8HlD30GsKgQR6HqxkbqmSY/+BioZbrQw=="

    shared_session = auth.from_bn(pow(subtracted, exponent, p))
    assert b64e(shared_session) == "MzmNFkOYBsWjwcOXii9mw7vA+Fbot6e581UI8V7QwbTa6gNkpT+p4mQA7CkhCTu9y9KdKvx/Z0xE/aW06R7CLzCjP9oggkEGH32Q5sfhMsdbaaZYUu81Mh9pMyzpvUGADpDBBHZmN1EkYn3By6hbpAmlyloR/uMA3Piev102j5PMnjKXB99Ady7s7HTfCh4IobV4hjPEfvhsFnem+TrNRFvGnPYJ9wJ0paYVgPH5/Fk18zNBRESsdJSReIN8ocEAdT0sRYfF+4C1g6YtRqxszNkCWlAn+hJunR6WFmYkKLMbNkVQLDPgkFek31h0THJNIdpXnL2hxqRsM6Hycli1ng=="


    # Don't randomly gen in the test
    auth.generate_random_bytes = lambda n: client_secret
    proofs = auth.generate_proofs(2048, modulus, hashed_password,
                                  server_ephemeral)

    assert b64e(proofs['client_ephemeral']) == "XTaTsmCVqIns4E8dmMNOHpGIvh0j6zXD2cFtRKpNaFNV1zgRyo1CtxwcZO1l3sSk6FqhdBpDZrafSoF4mJIlYhrI4pIxvKiTTVWH50pPDRP6pCA64sHsUgKazHGnM09u29FocjqcewN6Oe+ZIm+A8TnssDmGI80XSy1nhbbPcQCn+VeTGR7g2f3l/7AbEMKnzWg3sZ2NAuNSYQaG2Kd211ZuLgEPQzWxPS+8ePACoWYnS3bzDDi8JXEKM6aXIqcY1+WG6Y1mks7k+bLyt62YfuFnjUzygzmXx6cuaw6UHmuHnfoiObDU5qwM+/RPpvvOCQ7pqB3ufvhgpAm+YiSVdg=="
    assert b64e(proofs['client_proof']) == "hd3KIdpaF1//ZFchpVDsq9FpW5/XyXALcWfQiZplAmsr704RbbEUb2fa4O+icpPNXgcZeMk63bN9DFQRykoGzjTooiMPobJWHF5JNrHwBhSKNJnCqTCqIrP5vddzMJCE17+C4ITi4QMJOOFcX3SWP0Capm7U18dSQfHDtaTVtdpr+i3zUd+gU4KykQUtjhZ8j/9JAw24bECaQl1gLPuyULpfFaSZc5wzdKdW3hznYX9rQBJAaFSvqRcN06HhsyDxaswTunUbVAlMrTVMl0+L2HPQpAGp2c0e5KGoYDYwDP3+k4Qs/igQIngEu535m6hPTyvL4qqgKxlqErWucjiOAw=="
    assert b64e(proofs['server_proof']) == "PE6/te1IEulNJPsxRxo+g1RI0czOighWhZSHGHE1kojwysj6n/HE1YSkzV9fkWpKFaxWlQbunoeX2rXqbCPnBiUIDWVWc0ps5tB1uRTOuG249mtX+nXPpwTbN85E7NxERv1MBhaluQQ9CZkfa/B90Sjba4i7K3Ln+pYZ24ZXZnqipHixdDees6XS2Y02ZKYDrlNEJiSDXNUVRGlGatHY5halLWMnKe5jLnLfWZuaAvtFg+FOBLk9tqMf+8cohubjavDFv113a8bn+Sqg2R5rx18b3l/tvUCtEKpb8jDNis5D/xCQpHjVwl7+NhMHIWz6Dp0Fi8Mf9RmQRYe3TECc/w=="
Example #5
0
def test_access_token():
    auth.read_armored(AUTH['AccessToken'])
Example #6
0
    def _login(self, password, unlock=True):
        client = self.client
        host = self.host
        headers = self.headers.copy()
        headers.update({
            'Accept': 'application/vnd.protonmail.v1+json',
            'Referer': host + "login",
        })

        # Get the auth info
        r = yield requests.post(url=host + "api/auth/info",
                                json=client.to_json('Username', 'ClientID'),
                                headers=headers)

        if r.code != 200:
            try:
                data = yield r.json()
            except:
                data = {}
            raise LoginError("Unexpected info response: "
                             "{} - {}".format(r.code, data))
        data = yield r.json()

        # Parses the response and computes the proof
        resp = client.AuthInfo = responses.AuthInfoResponse.from_json(**data)
        if resp.Code != 1000:
            raise LoginError("Unexpected info code: {}".format(resp.Code))
        if resp.TwoFactor:
            raise NotImplementedError("Two factor auth is not implemented")

        # Compute the hashed password
        client.HashedPassword = auth.hash_password(
            int(client.ApiVersion), password, b64d(resp.Salt), client.Username,
            b64d(auth.read_armored(resp.Modulus)))

        # Update headers
        headers.update({
            'Accept': '*/*',
        })

        # Authenticate
        r = yield requests.post(
            url=host + "api/auth",
            json=client.to_json('Username',
                                'ClientID',
                                'ClientSecret',
                                'TwoFactorCode',
                                SRPSession=client.AuthInfo.SRPSession,
                                ClientProof=b64e(client.ClientProof),
                                ClientEphemeral=b64e(client.ClientEphemeral)),
            headers=headers)
        if r.code != 200:
            try:
                data = yield r.json()
            except:
                data = {}
            raise LoginError("Unexpected auth response: "
                             "{} - {}".format(r.code, data))

        data = yield r.json()

        resp = client.Auth = responses.AuthResponse.from_json(**data)
        if resp.Code != 1000:
            del client.Auth
            raise LoginError("Unexpected auth code: {}".format(resp.Code))
        if b64d(resp.ServerProof) != client.ExpectedServerProof:
            del client.Auth
            raise AuthError("Invalid server authentication")

        # Login success
        if not unlock:
            return_value(resp)

        # And unlock
        unlocked = yield self._unlock(password)
        return_value((resp, unlocked))