Skip to content
This repository has been archived by the owner on Aug 4, 2019. It is now read-only.

New provisioning format #43

Closed
pylover opened this issue Mar 18, 2018 · 17 comments
Closed

New provisioning format #43

pylover opened this issue Mar 18, 2018 · 17 comments
Assignees
Labels
enhancement new feature or request
Milestone

Comments

@pylover
Copy link
Member

pylover commented Mar 18, 2018

We need to add version and checksum elements.

@pylover pylover added the enhancement new feature or request label Mar 18, 2018
@pylover pylover self-assigned this Mar 18, 2018
@pylover pylover added this to the WhenPigsFly milestone Aug 25, 2018
@pylover pylover modified the milestones: WhenPigsFly, v1b1 Oct 28, 2018
@pylover
Copy link
Member Author

pylover commented Oct 28, 2018

New provisioning format: UPDATED

All byte-orders is Big-endian.

token = version(UnsignedByte:1)+expireDate(UnsignedInt:4)+cryptomoduleId(UnsignedByte:1)+seed(Byte:20)+name(Byte:6-50)+bankId(UnsignedByte:1)

token += checksum(token, length=4)
token = encrypt(token)
token = hexlify(token)  // Convert to hex-string: 0-9a-f

Example:

Field Length Value Binary Description
version 1 1 \x01 The provisioning version, current: 1
expireDate 4 220101 \x00\x03\x5b\xc5 2022-01-01
cryptomoduleId 1 1 \x01 Cryptomodule Id: 1-255
bankId 1 1 \x01 Bank Id:1-255
seed 20 abcdefghijklmnopqrst \x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74 Token's seed
name 14 abcdefghijklmn \x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e Token name

@pylover
Copy link
Member Author

pylover commented Oct 28, 2018

@EhsanMashhadi

@EhsanMashhadi
Copy link

@pylover Thanks. Would you please put a mock-up token in hex format and each field values? I want to write a test based on this token.

@EhsanMashhadi
Copy link

@pylover Where is IV? We need IV if you used CBC mode.

@pylover pylover changed the title Encrypt the seed before storing it on the database New provisioning format Oct 29, 2018
@pylover
Copy link
Member Author

pylover commented Oct 29, 2018

Yes.

Usually, we freeze our random function to return always the same result for IV, to pass our tests:

    def encrypt(self, data):
        cipher = AESCipher(
            self.secret,
            random=cryptohelpers.random  # Frozen
        )
        return cipher.encrypt(data)

Is it ok to deliver these frozen bytes to you for testing purposes?

@pylover
Copy link
Member Author

pylover commented Oct 29, 2018

class AESCipher(Cipher):

    def __init__(self, key, random=os.urandom):
        self.bs = 16
        self.key = key
        self.random = random

    def encrypt(self, raw):
        raw = self._pad(raw)
        iv = self.random(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return iv + cipher.encrypt(raw)

    def decrypt(self, enc):
        iv = enc[:AES.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        result = self._unpad(cipher.decrypt(enc[AES.block_size:]))
        if not result.strip():
            raise ValueError()
        return result

    def _pad(self, s):
        remaining_bytes = len(s) % self.bs
        padding_bytes = self.bs - remaining_bytes
        return s + padding_bytes * bytes([padding_bytes])

    @staticmethod
    def _unpad(s):
        return s[:-ord(s[len(s)-1:])]

@pylover
Copy link
Member Author

pylover commented Oct 31, 2018

A real-world example

Field Length Value Binary
version 1 1 \x01
expireDate 4 220101 \x00\x03\x5b\xc5
cryptomoduleId 1 1 \x01
bankId 1 2 \x02
seed 20 abcdefghijklmnopqrst \x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74
name 14 abcdefghijklmn \x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e

After bundling:

\x01\x00\x02\xe7\x06\x01\x04<\x02abcdefghijklmnopqrstabcdefghijklmn

After adding checksum

\x01\x00\x02\xe7\x06\x01\x04<\x02abcdefghijklmnopqrstabcdefghijklmn5540

After encrypt with IV=abcdefghijklmnop and secret=abcdefghijklmnopqrstuvwxyz123456

abcdefghijklmnop\x17\x05\xb3\xe0\x0f\xd3Qcb\r\xd9\x90\x15\x1dr\xf4&\x19\xee\xf5\x15\xd2\\\x08\xbe\xd9OD\x91\xbc 
\xf4\x9e\xbd\xe0\xb9j\xd9zA\x11\x0bNX\x8e\xeb4\xe7\xee

pylover added a commit that referenced this issue Oct 31, 2018
@pylover
Copy link
Member Author

pylover commented Oct 31, 2018

@EhsanMashhadi please use this script: to ensure eveything is working: https://github.com/Carrene/mobile-token-isc/blob/master/production/test-script.sh

@EhsanMashhadi
Copy link

@pylover Where is the IV in your provisioning format? Would you please add it to your table above?

@pylover
Copy link
Member Author

pylover commented Nov 4, 2018

Please check my recent comment:

After encrypt with IV=abcdefghijklmnop and secret=abcdefghijklmnopqrstuvwxyz123456

It will prepended to the token.

@EhsanMashhadi
Copy link

EhsanMashhadi commented Nov 9, 2018

A real-world example

Field Length Value Binary
version 1 1 \x01
expireDate 4 220101 \x00\x03\x5b\xc5
cryptomoduleId 1 1 \x01
seed 20 abcdefghijklmnopqrst \x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74
name 14 abcdefghijklmn \x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e
After bundling:

\x01\x00\x03[\xc5\x01abcdefghijklmnopqrstabcdefghijklmn

After adding checksum

\x01\x00\x03[\xc5\x01abcdefghijklmnopqrstabcdefghijklmn7518

After encrypt with IV=abcdefghijklmnop and secret=abcdefghijklmnopqrstuvwxyz123456

abcdefghijklmnop+X\xfe\xb1T7\x13\xe1M\t\xc2\xa0\xd6\x1a?\x9d\xfe/\x85\xb6\xe0\xeb\xc1\x0b\xc7*\\O\x89\x04\x04Q?\xb8\xa1\xe3\xb55\xc8C\x9bC(\xf0\xca\xaa\xc9\xf7

Would you please add hex format of the result (last value) here too?

@EhsanMashhadi
Copy link

EhsanMashhadi commented Nov 9, 2018

@pylover Would you please describe your checksum calculation?

h = hashlib.sha1(key)
    if data:
        h.update(data)
    digest = h.digest()

What does this code do?

@pylover
Copy link
Member Author

pylover commented Nov 17, 2018

A real-world example

(UPDATED after #78, Carrene/lion#14

token = version(UnsignedByte:1)+expireDate(UnsignedInt:4)+cryptomoduleId(UnsignedByte:1)+length(UnsignedByte:1)+timeInterval(UnsignedByte:1)+seed(Byte:20)+name(Byte:6-50)

token += checksum(token, length=4)
token = encrypt(token)
token = hexlify(token)  // Convert to hex-string: 0-9a-f
Field Length Value Binary
version 1 1 \x01
expireDate 4 220101 \x00\x03\x5b\xc5
cryptomoduleId 1 1 \x01
length 1 4 \x4
time_interval 1 60 \x3c
seed 20 abcdefghijklmnopqrst \x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74
name 14 abcdefghijklmn \x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e

After bundling:

bytestring: \x01\x00\x03[\xc5\x01\x04<abcdefghijklmnopqrstabcdefghijklmn
hexstring: 0100035bc501043c6162636465666768696a6b6c6d6e6f70717273746162636465666768696a6b6c6d6e

After adding checksum

bytestring: \x01\x00\x03[\xc5\x01\x04<abcdefghijklmnopqrstabcdefghijklmn3568
hexstring: '0100035bc501043c6162636465666768696a6b6c6d6e6f70717273746162636465666768696a6b6c6d6e33353638

After encrypt with IV=abcdefghijklmnop and secret=abcdefghijklmnopqrstuvwxyz123456

bytestring: abcdefghijklmnop\xa8\xb0\xe3\xcf\x9f\x12\x14\x86$J\x87<\x15\xa8T\xc9\xe1d~\x0fb\xe5\xee\x8c\x9f^\xda\xa9\xf0\xa9\xc0\x8f\xcf\xf3\x06\xfdr3O\x03\xcd3\x93\x81\xb1\xebnZ
hexstring: 6162636465666768696a6b6c6d6e6f70a8b0e3cf9f121486244a873c15a854c9e1647e0f62e5ee8c9f5edaa9f0a9c08fcff306fd72334f03cd339381b1eb6e5a
base64: YWJjZGVmZ2hpamtsbW5vcKiw48-fEhSGJEqHPBWoVMnhZH4PYuXujJ9e2qnwqcCPz_MG_XIzTwPNM5OBsetuWg==

@pylover
Copy link
Member Author

pylover commented Nov 17, 2018

@EhsanMashhadi

The server is ready. Please test it by:

#! /usr/bin/env bash

set -e
shopt -s expand_aliases
alias curl="curl -i -s --insecure"

HOST="192.168.1.57"
AGAMA="https://$HOST"
WOLF="http://$HOST:81"
LION="http://$HOST"
PHONE="98912145175"
UDID="2b6f0cc904d137be2e1730235f5664094b831186"

echo -n "Claiming device..."
curl -XCLAIM -s $AGAMA/apiv1/devices -F"phone=$PHONE" \
  -F"udid=$UDID" 2>&1 > /dev/null
echo
echo "done"

echo -n "Finding last activation token..."
ACTIVATION_CODE=`curl $AGAMA | tail -n1 | cut -d',' -f2`
echo "done: $ACTIVATION_CODE"

echo -n "Bidning the device..."
curl -XBIND -s $AGAMA/apiv1/devices -F"phone=$PHONE" \
  -F"udid=$UDID" \
  -F"name=MytestDevice" \
  -F"activationCode=$ACTIVATION_CODE"
echo

echo -n "Ensuring a token..."
curl 192.168.1.57:81/apiv1/tokens -XENSURE -F"phone=$PHONE" \
  -F"name=MiladSibil" -F"cryptomoduleId=1" -F"expireDate=1572264891"
echo
echo "done"

@EhsanMashhadi
Copy link

EhsanMashhadi commented Nov 18, 2018

A real-world example

(UPDATED after #78, Carrene/lion#14

token = version(UnsignedByte:1)+expireDate(UnsignedInt:4)+cryptomoduleId(UnsignedByte:1)+length(UnsignedByte:1)+timeInterval(UnsignedByte:1)+seed(Byte:20)+name(Byte:6-50)

token += checksum(token, length=4)
token = encrypt(token)
token = hexlify(token)  // Convert to hex-string: 0-9a-f

Field Length Value Binary
version 1 1 \x01
expireDate 4 220101 \x00\x03\x5b\xc5
cryptomoduleId 1 1 \x01
time_interval 1 60 \x3c
length 1 4 \x4
seed 20 abcdefghijklmnopqrst \x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74
name 14 abcdefghijklmn \x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e
After bundling:

bytestring: \x01\x00\x03[\xc5\x01\x04<abcdefghijklmnopqrstabcdefghijklmn
hexstring: 0100035bc501043c6162636465666768696a6b6c6d6e6f70717273746162636465666768696a6b6c6d6e

After adding checksum

bytestring: \x01\x00\x03[\xc5\x01\x04<abcdefghijklmnopqrstabcdefghijklmn3568
hexstring: '0100035bc501043c6162636465666768696a6b6c6d6e6f70717273746162636465666768696a6b6c6d6e33353638

After encrypt with IV=abcdefghijklmnop and secret=abcdefghijklmnopqrstuvwxyz123456

bytestring: abcdefghijklmnop\xa8\xb0\xe3\xcf\x9f\x12\x14\x86$J\x87<\x15\xa8T\xc9\xe1d~\x0fb\xe5\xee\x8c\x9f^\xda\xa9\xf0\xa9\xc0\x8f\xcf\xf3\x06\xfdr3O\x03\xcd3\x93\x81\xb1\xebnZ
hexstring: 6162636465666768696a6b6c6d6e6f70a8b0e3cf9f121486244a873c15a854c9e1647e0f62e5ee8c9f5edaa9f0a9c08fcff306fd72334f03cd339381b1eb6e5a
base64: YWJjZGVmZ2hpamtsbW5vcKiw48-fEhSGJEqHPBWoVMnhZH4PYuXujJ9e2qnwqcCPz_MG_XIzTwPNM5OBsetuWg==

@pylover

Timeinterval and length is not sync from your token and your comment.
In the token first one is the length then time interval but in your comment is vice versa. Which one is correct?

@EhsanMashhadi
Copy link

@EhsanMashhadi

The server is ready. Please test it by:

#! /usr/bin/env bash

set -e
shopt -s expand_aliases
alias curl="curl -i -s --insecure"

HOST="192.168.1.57"
AGAMA="https://$HOST"
WOLF="http://$HOST:81"
LION="http://$HOST"
PHONE="98912145175"
UDID="2b6f0cc904d137be2e1730235f5664094b831186"

echo -n "Claiming device..."
curl -XCLAIM -s $AGAMA/apiv1/devices -F"phone=$PHONE" \
  -F"udid=$UDID" 2>&1 > /dev/null
echo
echo "done"

echo -n "Finding last activation token..."
ACTIVATION_CODE=`curl $AGAMA | tail -n1 | cut -d',' -f2`
echo "done: $ACTIVATION_CODE"

echo -n "Bidning the device..."
curl -XBIND -s $AGAMA/apiv1/devices -F"phone=$PHONE" \
  -F"udid=$UDID" \
  -F"name=MytestDevice" \
  -F"activationCode=$ACTIVATION_CODE"
echo

echo -n "Ensuring a token..."
curl 192.168.1.57:81/apiv1/tokens -XENSURE -F"phone=$PHONE" \
  -F"name=MiladSibil" -F"cryptomoduleId=1" -F"expireDate=1572264891"
echo
echo "done"

The server just reply with phone = "192.168.1.57" otherwise I get

{"stackTrace":"Traceback (most recent call last):\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/nanohttp\/application.py\", line 108, in __call__\n    response_body = self.__root__(*remaining_paths)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/restfulpy\/controllers.py\", line 21, in __call__\n    return super().__call__(*remaining_paths)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/nanohttp\/controllers.py\", line 110, in __call__\n    return self._serve_handler(handler, remaining_paths)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/nanohttp\/controllers.py\", line 104, in _serve_handler\n    return handler(*remaining_paths, **kwargs)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/nanohttp\/controllers.py\", line 110, in __call__\n    return self._serve_handler(handler, remaining_paths)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/nanohttp\/controllers.py\", line 104, in _serve_handler\n    return handler(*remaining_paths, **kwargs)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/wolf\/controllers.py\", line 57, in __call__\n    return super().__call__(*remaining_paths)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/nanohttp\/controllers.py\", line 110, in __call__\n    return self._serve_handler(handler, remaining_paths)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/nanohttp\/controllers.py\", line 104, in _serve_handler\n    return handler(*remaining_paths, **kwargs)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/nanohttp\/decorators.py\", line 133, in wrapper\n    result = func(*args, **kwargs)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/nanohttp\/validation.py\", line 313, in wrapper\n    return func(*args, **kwargs)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/restfulpy\/orm\/models.py\", line 250, in wrapper\n    result = func(*args, **kwargs)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/restfulpy\/orm\/__init__.py\", line 84, in wrapper\n    result = func(*args, **kwargs)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/wolf\/controllers.py\", line 110, in ensure\n    result['provisioning'] = token.provision(phone)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/wolf\/models.py\", line 114, in provision\n    encrypted_binary = LionClient().encrypt(phone, binary, checksum=4)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/wolf\/backends.py\", line 47, in encrypt\n    dict(data=data, checksumLength=checksum)\n  File \"\/usr\/local\/lib\/python3.6\/site-packages\/wolf\/backends.py\", line 34, in _request\n    raise SSMInternalError()\nwolf.exceptions.SSMInternalError: 802 SSM internal error\n"}

@masoodkamyab
Copy link
Contributor

This issue migrated to #86

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement new feature or request
Projects
None yet
Development

No branches or pull requests

3 participants