1*e1fe3e4aSElliott Hughes""" 2*e1fe3e4aSElliott HughesPostScript Type 1 fonts make use of two types of encryption: charstring 3*e1fe3e4aSElliott Hughesencryption and ``eexec`` encryption. Charstring encryption is used for 4*e1fe3e4aSElliott Hughesthe charstrings themselves, while ``eexec`` is used to encrypt larger 5*e1fe3e4aSElliott Hughessections of the font program, such as the ``Private`` and ``CharStrings`` 6*e1fe3e4aSElliott Hughesdictionaries. Despite the different names, the algorithm is the same, 7*e1fe3e4aSElliott Hughesalthough ``eexec`` encryption uses a fixed initial key R=55665. 8*e1fe3e4aSElliott Hughes 9*e1fe3e4aSElliott HughesThe algorithm uses cipher feedback, meaning that the ciphertext is used 10*e1fe3e4aSElliott Hughesto modify the key. Because of this, the routines in this module return 11*e1fe3e4aSElliott Hughesthe new key at the end of the operation. 12*e1fe3e4aSElliott Hughes 13*e1fe3e4aSElliott Hughes""" 14*e1fe3e4aSElliott Hughes 15*e1fe3e4aSElliott Hughesfrom fontTools.misc.textTools import bytechr, bytesjoin, byteord 16*e1fe3e4aSElliott Hughes 17*e1fe3e4aSElliott Hughes 18*e1fe3e4aSElliott Hughesdef _decryptChar(cipher, R): 19*e1fe3e4aSElliott Hughes cipher = byteord(cipher) 20*e1fe3e4aSElliott Hughes plain = ((cipher ^ (R >> 8))) & 0xFF 21*e1fe3e4aSElliott Hughes R = ((cipher + R) * 52845 + 22719) & 0xFFFF 22*e1fe3e4aSElliott Hughes return bytechr(plain), R 23*e1fe3e4aSElliott Hughes 24*e1fe3e4aSElliott Hughes 25*e1fe3e4aSElliott Hughesdef _encryptChar(plain, R): 26*e1fe3e4aSElliott Hughes plain = byteord(plain) 27*e1fe3e4aSElliott Hughes cipher = ((plain ^ (R >> 8))) & 0xFF 28*e1fe3e4aSElliott Hughes R = ((cipher + R) * 52845 + 22719) & 0xFFFF 29*e1fe3e4aSElliott Hughes return bytechr(cipher), R 30*e1fe3e4aSElliott Hughes 31*e1fe3e4aSElliott Hughes 32*e1fe3e4aSElliott Hughesdef decrypt(cipherstring, R): 33*e1fe3e4aSElliott Hughes r""" 34*e1fe3e4aSElliott Hughes Decrypts a string using the Type 1 encryption algorithm. 35*e1fe3e4aSElliott Hughes 36*e1fe3e4aSElliott Hughes Args: 37*e1fe3e4aSElliott Hughes cipherstring: String of ciphertext. 38*e1fe3e4aSElliott Hughes R: Initial key. 39*e1fe3e4aSElliott Hughes 40*e1fe3e4aSElliott Hughes Returns: 41*e1fe3e4aSElliott Hughes decryptedStr: Plaintext string. 42*e1fe3e4aSElliott Hughes R: Output key for subsequent decryptions. 43*e1fe3e4aSElliott Hughes 44*e1fe3e4aSElliott Hughes Examples:: 45*e1fe3e4aSElliott Hughes 46*e1fe3e4aSElliott Hughes >>> testStr = b"\0\0asdadads asds\265" 47*e1fe3e4aSElliott Hughes >>> decryptedStr, R = decrypt(testStr, 12321) 48*e1fe3e4aSElliott Hughes >>> decryptedStr == b'0d\nh\x15\xe8\xc4\xb2\x15\x1d\x108\x1a<6\xa1' 49*e1fe3e4aSElliott Hughes True 50*e1fe3e4aSElliott Hughes >>> R == 36142 51*e1fe3e4aSElliott Hughes True 52*e1fe3e4aSElliott Hughes """ 53*e1fe3e4aSElliott Hughes plainList = [] 54*e1fe3e4aSElliott Hughes for cipher in cipherstring: 55*e1fe3e4aSElliott Hughes plain, R = _decryptChar(cipher, R) 56*e1fe3e4aSElliott Hughes plainList.append(plain) 57*e1fe3e4aSElliott Hughes plainstring = bytesjoin(plainList) 58*e1fe3e4aSElliott Hughes return plainstring, int(R) 59*e1fe3e4aSElliott Hughes 60*e1fe3e4aSElliott Hughes 61*e1fe3e4aSElliott Hughesdef encrypt(plainstring, R): 62*e1fe3e4aSElliott Hughes r""" 63*e1fe3e4aSElliott Hughes Encrypts a string using the Type 1 encryption algorithm. 64*e1fe3e4aSElliott Hughes 65*e1fe3e4aSElliott Hughes Note that the algorithm as described in the Type 1 specification requires the 66*e1fe3e4aSElliott Hughes plaintext to be prefixed with a number of random bytes. (For ``eexec`` the 67*e1fe3e4aSElliott Hughes number of random bytes is set to 4.) This routine does *not* add the random 68*e1fe3e4aSElliott Hughes prefix to its input. 69*e1fe3e4aSElliott Hughes 70*e1fe3e4aSElliott Hughes Args: 71*e1fe3e4aSElliott Hughes plainstring: String of plaintext. 72*e1fe3e4aSElliott Hughes R: Initial key. 73*e1fe3e4aSElliott Hughes 74*e1fe3e4aSElliott Hughes Returns: 75*e1fe3e4aSElliott Hughes cipherstring: Ciphertext string. 76*e1fe3e4aSElliott Hughes R: Output key for subsequent encryptions. 77*e1fe3e4aSElliott Hughes 78*e1fe3e4aSElliott Hughes Examples:: 79*e1fe3e4aSElliott Hughes 80*e1fe3e4aSElliott Hughes >>> testStr = b"\0\0asdadads asds\265" 81*e1fe3e4aSElliott Hughes >>> decryptedStr, R = decrypt(testStr, 12321) 82*e1fe3e4aSElliott Hughes >>> decryptedStr == b'0d\nh\x15\xe8\xc4\xb2\x15\x1d\x108\x1a<6\xa1' 83*e1fe3e4aSElliott Hughes True 84*e1fe3e4aSElliott Hughes >>> R == 36142 85*e1fe3e4aSElliott Hughes True 86*e1fe3e4aSElliott Hughes 87*e1fe3e4aSElliott Hughes >>> testStr = b'0d\nh\x15\xe8\xc4\xb2\x15\x1d\x108\x1a<6\xa1' 88*e1fe3e4aSElliott Hughes >>> encryptedStr, R = encrypt(testStr, 12321) 89*e1fe3e4aSElliott Hughes >>> encryptedStr == b"\0\0asdadads asds\265" 90*e1fe3e4aSElliott Hughes True 91*e1fe3e4aSElliott Hughes >>> R == 36142 92*e1fe3e4aSElliott Hughes True 93*e1fe3e4aSElliott Hughes """ 94*e1fe3e4aSElliott Hughes cipherList = [] 95*e1fe3e4aSElliott Hughes for plain in plainstring: 96*e1fe3e4aSElliott Hughes cipher, R = _encryptChar(plain, R) 97*e1fe3e4aSElliott Hughes cipherList.append(cipher) 98*e1fe3e4aSElliott Hughes cipherstring = bytesjoin(cipherList) 99*e1fe3e4aSElliott Hughes return cipherstring, int(R) 100*e1fe3e4aSElliott Hughes 101*e1fe3e4aSElliott Hughes 102*e1fe3e4aSElliott Hughesdef hexString(s): 103*e1fe3e4aSElliott Hughes import binascii 104*e1fe3e4aSElliott Hughes 105*e1fe3e4aSElliott Hughes return binascii.hexlify(s) 106*e1fe3e4aSElliott Hughes 107*e1fe3e4aSElliott Hughes 108*e1fe3e4aSElliott Hughesdef deHexString(h): 109*e1fe3e4aSElliott Hughes import binascii 110*e1fe3e4aSElliott Hughes 111*e1fe3e4aSElliott Hughes h = bytesjoin(h.split()) 112*e1fe3e4aSElliott Hughes return binascii.unhexlify(h) 113*e1fe3e4aSElliott Hughes 114*e1fe3e4aSElliott Hughes 115*e1fe3e4aSElliott Hughesif __name__ == "__main__": 116*e1fe3e4aSElliott Hughes import sys 117*e1fe3e4aSElliott Hughes import doctest 118*e1fe3e4aSElliott Hughes 119*e1fe3e4aSElliott Hughes sys.exit(doctest.testmod().failed) 120