DeviceSal Dict 000 (EKB) -> (status): Verify EKB file. For version 1, check SHA-1 of first 176 bytes. For any other, call DeviceSal Dict 159. Returns 0 if OK, otherwise an error code. DeviceSal Dict 001 DeviceSal Dict 002 DeviceSal Dict 003 DeviceSal Dict 159(0x9f) (EKB) -> (status): Verify EKB file with version > 1. Checks ECC signature, returns 0 if OK, otherwise an error code. DeviceSal Dict 160(0xa0) DeviceSal Dict 165(0xa5) DeviceSal Dict 170(0xaa) DeviceSal Dict 171(0xab) DeviceSal Dict 172(0xac): Dispatch table for D171. DeviceSal Dict 173(0xad) DeviceSal Dict 174(0xae) DeviceSal Dict 175(0xaf) DeviceSal Dict 177(0xb1) DeviceSal Dict 178(0xb2): Dispatch table for D177. DeviceSal Dict 180(0xb4) (a,b,c) -> (1): Returns 1. DeviceSal Dict 181(0xb5) (deskey,plain,cipher,xorout,xorin) -> (): DES-ECB-Encrypt "plain XORrep xorin" and set cipher to "that XORrep xorout". DeviceSal Dict 182(0xb6) DeviceSal Dict 183(0xb7) DeviceSal Dict 184(0xb8 (msg,tripdeskey) -> (mac): tripdeskey has two keys (2*8 bytes), say k1 ++ k2. DES-CBC-Encrypt msg with k1, then DES-Decrypt the last block with k2, DES-Encrypt that with k1, and return the single block result. DeviceSal Dict 185(0xb9) (cipher,iv,enckey2,encobj,key) -> (plain): DES-OCM-Decrypt encobj with "key", the plaintext is a 3DES key k1 ++ k2. DES-Decrypt enckey2 with k2, DES-Encrypt that with k1, resulting in key2. DES-CBC-Decrypt cipher with key2 and iv and return the result. DeviceSal Dict 186(0xba) (plain,iv,encobj,key) -> (nkey,cipher): DES-OCM-Decrypt encobj with "key", the plaintext is a 3DES key k1 ++ k2. Then create a new key, and encrypt it with k2, that's nkey. Also encrypt the new key with k1, and use that to DES-CBC-Encrypt plain with iv into cipher. DeviceSal Dict 187(0xbb) DeviceSal Dict 189(0xbd) (key,value) -> (): Use D191 as a map and enter (key, value) into it. DeviceSal Dict 190(0xbe) (key,default) -> (): Use D191 as map and return the value for key, or default if not found. DeviceSal Dict 191(0xbf): Variable to pass mapping to helper functions. DeviceSal Dict 193(0xc1) DeviceSal Dict 194(0xc2) DeviceSal Dict 195(0xc3) DeviceSal Dict 196(0xc4) DeviceSal Dict 197(0xc5): Dispatch table for 196. DeviceSal Dict 198(0xc6): (Decrypto with hook D249, reencrypt with DES-OCM) DeviceSal Dict 199(0xc7) DeviceSal Dict 207(0xcf) (encobj, objkey) -> (...): DES-OCM-Decrypt encobj with objkey and unpack an ASN.1 encoded array (stripping off the length parameter) DeviceSal Dict 208(0xd0) (o1, o2, objkey) -> (encobj): DES-OCM-Encrypt an ASN.1 encoded array containing the first 8 bytes of o1 and o2 each. DeviceSal Dict 209(0xd1) (version) -> (ekbpath): Return the local EKB path. DeviceSal Dict 210(0xd2) () -> (1): Produce 1. DeviceSal Dict 211(0xd3) DeviceSal Dict 212(0xd4) DeviceSal Dict 213(0xd5) DeviceSal Dict 214(0xd6) (encobj, protokey) -> (obj): Descramble cipher and OCM-Decrypt with SHA-1(protokey) and ASN.1-decode the result. DeviceSal Dict 215(0xd7) (obj, protokey) -> (encobj): OCM-Encrypt the serialized obj with SHA-1(protokey) and scramble the result. DeviceSal Dict 216(0xd8) (encobj, xorprotokey) -> (obj): DES-OCM-Decrypt with SHA-1(xorprotokey XOR D252++D252) and ASN.1-decode the result. DeviceSal Dict 217(0xd9) (obj, xorprotokey) -> (encobj): DES-OCM-Encrypt the serialized obj with SHA-1(xorprotokey XOR D252++D252). DeviceSal Dict 220(0xdc) (cipher, key) -> (plain): Decrypt with some weird SHA-1 based stream cipher. DeviceSal Dict 221(0xdd) (plain, key) -> (cipher): Encrypt with some weird SHA-1 based stream cipher. Missing Info: Dict 0xfc - contains an unknown 8 byte key, used in dev_0xd8, dev_0xd9. Native modules: // CBC Encrypt/Decrypt. The OUT buffer must be pre-allocated. // Block size of the cipher is 64 bit, key length is 160 bit. blob_t native::ocmmod (blob_t in, blob_t out, blob_t key, int len, int decrypt) { if (decrypt) ocmmod_cbc_decrypt (in, out, key, len); else ocmmod_cbc_encrypt (in, out, key, blob_len (in)); return out; } int dev_0x01 (blob_t someblob, bool_t somebool) { int res; if (somebool == 1) { res = dev_0x00 (someblob); if (res != 0) return res; } int some_nr = (unsigned) SubBlob (someblob, 0, 4); int some_nr2 = (unsigned) dev_0xd1 (some_nr); res = "localekb" (some_nr2); // FIXME: Don't know the stack layout after this. if (res != 0) return; // but what? blob_t someblob2; // probably from localekb int some_nr3 = (signed) SubBlob (someblob2, 0, 4) + 1; vector vec; do { vec.append (SubBlob (some_nr3 * 16, 24)); } while (some_nr3-- >= 0); int some_nr3 = (signed) SubBlob (someblob2, 0, 4); res = dev_0xc1 (some_nr3); if (res != 0) return res; int some_nr4 = (signed) SubBlob (someblob2, 16, 4); if (some_nr3 == some_nr4) return 0; else return 8; // is vec returned as well? it's still on the stack. } int dev_0xb7 (any_t thing) { if (get_type (thing) != TYPE_BLOB) return 0; if (thing[2] == 0x31) return 2; else { if (! strncmp (thing, "\x31\x31", 2)) return 1; else return 0; } } block_t dev_0xd1 (int nr) { if (nr > 1) { 0x80 ("Invalid version..."); return 0; } else { return 00 81 00 00 00 00 00 00; } } // Some decrypt function. // KEYBLOB seems to be 16 byte in practice. any_t dev_0xd8 (blob_t ciphertext, blob_t keyblob) { blob_t key = keyblob XOR concat (dict[0xfc], dict[0xfc]); // Side-effect. dict[0xdb] = key; blob_t hashed_key = SHA1 (key[0..14]); blob_t des_iv = hashed_key[0..7]; blob_t des_key = hashed_key[8..15] blob_t data = DES_CBC_Decrypt (ciphertext, des_iv, des_key, 0xd8_DESDecrypt); // Decrypt with ocmmod cipher. int len = blob_length (data); // Round up to multiple of 8. len = (len + 7) / 8 * 8; blob_t plaintext = repeat_nul (len); plaintext = native::ocmmod (data, plaintext, hashed_key, len, 1); // Return deserialized object. return decode_asn1 (plaintext); } // Some encrypt function. // KEYBLOB seems to be 16 byte in practice. blob_t dev_0xd9 (any_t plainobj, blob_t keyblob) { blob_t key = keyblob XOR concat (dict[0xfc], dict[0xfc]); // Side-effect. dict[0xdb] = key; // Serialization. plaintext = encode_asn1 (plaintext); // Encrypt with ocmmod cipher. int len = blob_length (data); // Round up to multiple of 8. len = (len + 7) / 8 * 8; blob_t data = repeat_nul (len); blob_t hashed_key = SHA1 (key[0..14]); data = native::ocmmod (plaintext, data, hashed_key, len, 0); // Encrypt DES. blob_t des_iv = hashed_key[0..7]; blob_t des_key = hashed_key[8..15] blob_t ciphertext = DES_CBC_Decrypt (data, des_iv, des_key, 0xd7_DESEncrypt); return ciphertext; } NOT part of device.sal, but for lack of a better place, here an example of SsaTrans on updater.ocm: $ SsaTrans updater.ocm BCSeedRand63 (1, "j5\162\GS\140<,\f"); BCSetCryptTable ("L\225\164\152\DC1\RSD?\216f\198!\196\154\154\201\195b \192l^V\176r\245\151*\245[[\DC1\NULV#"...); v_39 = BCNewBlob (8); v_41 = BCDES_SetKey ("\188k\180(\150\EOT,\138"); arg_0 = Unknown v_43 = BCDES_CBC BCDDecrypt (arg_0, v_39, v_41, "\216"); v_44 = BCBlobLength (v_43); v_46 = BCBlobLength (""); v_49 = BCSubBlob (v_43, v_44 - v_46, -1); v_51 = BCCompareBlob (v_49, ""); if (v_51 == 0) [1 -> 1] { return [v_43, 1]; } else [1 -> 1] { return [0]; } v_56 = BCIfElse (v_43); v_57 = BCSerialize (v_56); return v_57;