aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/ocb.py
blob: 7383ee6031ebf5c178f37a94a62507eaedc4fcb2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#-*- coding: utf-8 -*-
from aespython import key_expander, aes_cipher, ocb_mode
import json
import base64

class sjcl(ocb_mode.OCBMode):
    """convenience class to wrap the sjcl objects encryption and decryption"""
    def __init__(self, key, keylen):
        KE = key_expander.KeyExpander(keylen)
        expended_key = KE.expand(key)
        cipher = aes_cipher.AESCipher(expanded_key)
        ocb_mode.OCBMode.__init__(self, cipher, len(key))

    @staticmethod
    def hex2byte(hexstring):
        """convert a hexstring to a list of bytes"""
        return map(ord, hexstring.decode("hex"))

    @staticmethod
    def byte2hex(byteslist):
        """convert a list of bytes to a hexstring"""
        return str(bytearray(byteslist)).encode("hex")
    
    @staticmethod
    def pad(b64string):
        """pad a base64 string with = so that its lengh is divisible by 4"""
        return b64string + ''.join(['='] * (len(b64string) % 4))

    def encrypt_sjclobject(self, plaintext, header):
        """encrypt a message and return in in the sjcl object format"""
        tag, ciphertext = ocb_mode.OCBMode.encrypt_block(self, plaintext, header)
        sjcl_object = {"iv": base64.b64encode(bytearray(self._iv)).rstrip("="),
                       "mode": "ocb2",
                       "ts": 128,
                       "ct": base64.b64encode(bytearray(ciphertext) +
                                              bytearray(tag)).rstrip("="),
                       "adata": base64.b64encode(header).rstrip("=")
                  }
        return json.dumps(sjcl_object)

    def decrypt_sjclobject(self, objectstring):
        """takes a sjcl object and return a list of bytes."""
        sjcl_object = json.loads(objectstring)
        iv = map(ord, base64.b64decode(pad(sjcl_object['iv'])))
        self.set_iv(iv)
        ct = map(ord, base64.b64decode(pad(sjcl_object['ct'])))
        try:
            header = map(ord, base64.b64decode(pad(sjcl_object['adata'])))
        except KeyError:
            header = []
        #sjcl appends the tag at the end of the cipher text (it's 16 bytes long)
        tag = ct[-16:]
        ciphertext = ct[:-16]
        isValid, plaintext = ocb_mode.OCBMode.decrypt_block(self, header, ciphertext, tag)
        if not isValid:
            raise Exception("can't authenticate the data")
        else:
            return plaintext
        
if __name__=="__main__":
    key = sjcl.hex2byte('12538243c49f1c58e6f7b0687bbd65b2')
    iv = sjcl.hex2byte('250c3041c00a605a4100e264abbc588b')
    sjclmode = sjcl(key, 128)
    sjclmode.set_iv(iv)
    plaintext = map(ord, "La chaire est triste, hélas ! et j'ai lu \
tous les livres.")
    header = bytearray("Mallarmé")
    test = sjclmode.encrypt_sjclobject(plaintext, header)   
    print test
    print str(bytearray(sjclmode.decrypt_sjclobject(test)))