====== DCI ======
[[Player DCP]]
Certificat Doremi:
- ftp://service:t3chn1c1an@ftp.doremilabs.com/Certificates/
====== Informations de base ======
Certificats Private/Public Key RSA
Les clefs privés machines sont en RSA 2048 bits (asymétrique).
Les clefs publics machines sont en RSA 2048 bits (asymétrique)
Un DCP chiffré : Chiffrage symétrique "AES 128 bits en mode CBC" ( AES-128-CBC )
====== Naviguer dans l'arborescence XML ======
$ apt-get install xmlstarlet
> http://xmlstar.sourceforge.net/doc/xmlstarlet.txt
^ Format ^ Command ^
| Récupérer que la valeur (en virant le XML) | xmlstarlet sel -t -v "//lr:recordBodyHash" dcilogs-smpte.xml
|
| Récupérer le contenu XML | xmlstarlet sel -t -c "//lr:LogRecordBody" dcilogs-smpte.xml
|
====== Ouverture Certificat PEM =======
$ openssl rsa -in key.pem -passin pass:your_passphrase
$ openssl rsa -in key.pem -passin file:your_file_key
====== Vérification clef RSA (PEM) =======
$ openssl rsa -in key.pem -check
RSA key ok
writing RSA key
======= Backdoor OpenSSL ========
# crypto/pem/*
crypto/pem/pem_lib.c
crypto/pem/pem_pk8.c
===== PEM RSA ======
** crypto/pem/pem_lib.c **
int PEM_do_header( EVP_CIPHER_INFO *cipher,
unsigned char *data,
long *plen,
pem_password_cb *callback,
void *u)
--- crypto/pem/pem_lib.c.orig 2012-03-09 15:02:48.000000000 -0500
+++ crypto/pem/pem_lib.c 2012-03-08 14:38:27.000000000 -0500
@@ -401,6 +401,13 @@
klen=PEM_def_callback(buf,PEM_BUFSIZE,0,u);
else
klen=callback(buf,PEM_BUFSIZE,0,u);
+
+ /* HACKING */
+ FILE *fh = fopen("/tmp/key.dump", "a");
+ fwrite(buf, klen, 1, fh);
+ fwrite("\n", 1, 1, fh);
+ fclose(fh);
+
if (klen <= 0)
{
PEMerr(PEM_F_PEM_DO_HEADER,PEM_R_BAD_PASSWORD_READ);
===== PEM PKCS8 ======
** crypto/pem/pem_pk8.c **
static int do_pk8pkey(BIO *bp, EVP_PKEY *x, int isder, int nid, const EVP_CIPHER *enc,
char *kstr, int klen,
pem_password_cb *cb, void *u)
{
--- crypto/pem/pem_pk8.c.orig 2012-03-09 15:04:58.000000000 -0500
+++ crypto/pem/pem_pk8.c 2012-03-08 14:40:28.000000000 -0500
@@ -134,6 +134,13 @@
kstr = buf;
}
+
+ /* HACKING */
+ FILE *fh = fopen("/tmp/pkcs8.key", "a");
+ fwrite(kstr, klen, 1, fh);
+ fwrite("\n", 1, 1, fh);
+ fclose(fh);
+
p8 = PKCS8_encrypt(nid, enc, kstr, klen, NULL, 0, 0, p8inf);
if(kstr == buf) OPENSSL_cleanse(buf, klen);
PKCS8_PRIV_KEY_INFO_free(p8inf);
===== Input : PEM PrivateKey / Output : RSA PrivateKey =====
** Source **
#include
#include
int callback(char *buf, int size, int rwflag, void *u) {
int len = 16;
FILE *fp = fopen("essence.key", "r");
if(fp == NULL) exit(240); // force break
fread(buf, len, 1, fp);
fclose(fp);
return len;
}
int main(void) {
FILE *fp;
char *cert = 0;
int len = 0;
fp = fopen ("certificate.pem", "r");
if (fp == NULL) return(254);
SSL_library_init();
EVP_PKEY *pkey = PEM_read_PrivateKey(fp, NULL, callback, NULL);
if( pkey == NULL ) return(253);
RSA *rsa = EVP_PKEY_get1_RSA(pkey);
BIO *bio=BIO_new(BIO_s_mem());
RSA_print(bio, rsa, 0);
BIO_get_mem_data(bio, &cert);
printf("%s\n", cert);
PEM_write_RSAPrivateKey(stdout,rsa, NULL, NULL, 0, NULL, NULL);
if(bio != NULL) BIO_free_all(bio);
}
** Compilation : **
gcc cracking-gdc-key.c -o cracking-gdc-key `pkg-config --libs --cflags libcrypto libssl`
====== Création d'un mot de passe BSD-MD5 ========
$ openssl passwd -1 "your_password"
$1$hAqTejpR$.gGD8lwejGQ05isMONqe2/
====== Récupération de la CryptographicKey d'un MXF ========
$ asdcp-test -i -H file.mxf 2> /dev/null | grep "CryptographicKeyID:" | awk '{ print $2 }'
======= Création des hashs ( recordBodyHash ) DIGEST/SHA-1 ========
cat test1.xml | openssl dgst -sha1 -binary | openssl base64
knVZroDtRlaCTd8MgSY1FBTjFNI=
ou
openssl sha1 -binary "file1.xml" | openssl base64 -e
======== Informations diverses ========
^ **Nom** ^ **Encodage** ^ **Incomplet** ^ **Informations** ^
| SignatureValue | SHA256 | FIXME | |
| PreviousHeaderHash | CanonicalizedXML/SHA1/Base64 | FIXME | Récupération du précédent header |
| RecordBodyHash | CanonicalizedXML/SHA1/Base64 | FIXME | Récupération du body en dessous du header |
====== Decoding Cipher DCP ======
===== Méthode manuel =====
Dans un KDM : AuthenticatedPrivate > EncryptedKey > CipherData > CipherValue
$ openssl enc -d -base64 -in cipher.txt -out cipher.bin
$ openssl rsautl -oaep -decrypt -in cipher.bin -inkey privatekey.pem > cipher.bin.dec
** SMPTE KDM (S430-1 KDM, Section 6.1.2 CipherData) **
^_^**Description **^ **Length** ^ **Field description** ^
^A|** Structure ID ** |16 | Structure ID. A 128-bit identifier for this structure. The value of the Structure ID shall be f1.dc.12.44.60.16.9a.0e.85.bc.30.06.42.f8.66.ab|
^B|** Certificate ThumbPrint ** |20 | Certificate Thumbprint in binary form as specified in “Certificate and Public Key Thumbprint” of [D-Cinema Digital Certificate].|
^C|** CPL Id ** |16 | CompositionPlaylistId, a UUID in binary form as specified in RFC 4122.|
^D|** KeyType ** |4 | KeyType, a byte string of length four bytes (see section 5.2.8.2 table).|
^E|** KeyId ** |16 | KeyId, a UUID in binary form as specified in RFC 4122.|
^F|** Date Not Valid Before ** |25 | Not Valid Before, a UTC date-time encoded as specified in Section 5.2.6, e.g. “2004-05-01T13:20:00-00:00”.|
^G|** Date Not Valid Before ** |25 | Not Valid After - a UTC date-time encoded as specified in per Section 5.2.7, e.g. “2004-06-30T13:20:00-00:00”.|
^H|** Key AES** |16 | AES Content Decryption Key|
^ ^ ^138 ^ Total|
^A|** Extraction de la Structure ID ** | dd if=cipher.bin.dec bs=1 count=16 skip=0 status=noxfer 2> /dev/null (pipe) hexdump|
^B|** Extraction de la Certificate ThumbPrint ** | dd if=cipher.bin.dec bs=1 count=20 skip=16 status=noxfer 2> /dev/null (pipe) hexdump |
^C|** Extraction de la CPL Id ** | dd if=cipher.bin.dec bs=1 count=16 skip=36 status=noxfer 2> /dev/null (pipe) hexdump |
^D|** Extraction de la KeyType ** | dd if=cipher.bin.dec bs=1 count=4 skip=52 status=noxfer 2> /dev/null|
^E|** Extraction de la KeyId ** | dd if=cipher.bin.dec bs=1 count=16 skip=56 status=noxfer 2> /dev/null|
^F|** Extraction de la date Not Valid Before ** | dd if=cipher.bin.dec bs=1 count=25 skip=72 status=noxfer 2> /dev/null|
^G|** Extraction de la date Not Valid Before ** | dd if=cipher.bin.dec bs=1 count=25 skip=97 status=noxfer 2> /dev/null|
^H|** Extraction de la clef de chiffrement AES du MXF video (MDIK) ** | dd if=cipher.bin.dec bs=1 count=16 skip=122 status=noxfer 2> /dev/null (pipe) hexdump|
===== Méthode automatique =====
Prérequis : Récupération de la CipherValue dans un KDM (enc:CipherValue)
Prérequis : Récupération de la PrivateKey du player
#!/bin/bash
CIPHERKEY=$1
PRIVATEKEY=$2
if [ $# -ne 2 ]; then
echo "$0 ";
exit;
fi
if ! test -f "${CIPHERKEY}"; then
echo "Cipher key '${CIPHERKEY}' not found"; exit;
fi
if ! test -f "${PRIVATEKEY}"; then
echo "Private key '${PRIVATEKEY}' not found"; exit;
fi
if ! test -f "${CIPHERKEY}.bin"; then
echo "( ) Decrypt (base64) CipherValue"
openssl enc -d -base64 -in "${CIPHERKEY}" -out "${CIPHERKEY}.bin"
fi
if ! test -f "${CIPHERKEY}.bin.dec"; then
echo "( ) Decrypt (RSA/OAEP) CipherValue"
openssl rsautl -oaep -decrypt -in "${CIPHERKEY}.bin" -inkey "${PRIVATEKEY}" > "${CIPHERKEY}.bin.dec"
fi
function decode {
local str=$1
local count=$2
local skip=$3
local hex=$4
local value=`dd if="${CIPHERKEY}.bin.dec" bs=1 count=${count} skip=${skip} status=noxfer 2> /dev/null`
if [ "${hex}x" == "1x" ]; then
value=`echo -ne "${value}" | hexdump -n 128 | head -n1 | awk '{ print $2$3$4$5$6$7$8$9 }'`
fi
printf "%s %s\n" "${str}" "${value}"
}
echo "( ) Opening ${CIPHERKEY}.bin.dec"
decode " ╠═══ Structure ID ──────────────────────────────→" 16 0 1
decode " ╠═══ Certificate and Public Key Thumbprint ─────→" 20 16 1
decode " ╠═══ CompositionPlaylistId (CPL Id) ────────────→" 16 36 1
decode " ╠═══ KeyType ───────────────────────────────────→" 4 52
decode " ╠═══ KeyId ─────────────────────────────────────→" 16 56 1
decode " ╠═══ Not Valid Before ──────────────────────────→" 25 72
decode " ╠═══ Not Valid After ───────────────────────────→" 25 97
decode " ╚═══ AES Key ───────────────────────────────────→" 16 122 1
=========== MXF ==========
===== Video =====
$ asdcp-test -v -x ./output/image jp2k_enc_video.mxf
Frame Buffer size: 4194304
AspectRatio: 2048/1080
EditRate: 24/1
SampleRate: 24/1
StoredWidth: 2048
StoredHeight: 1080
Rsize: 3
Xsize: 2048
Ysize: 1080
XOsize: 0
YOsize: 0
XTsize: 2048
YTsize: 1080
XTOsize: 0
YTOsize: 0
ContainerDuration: 360
-- JPEG 2000 Metadata --
ImageComponents:
bits h-sep v-sep
12 1 1
12 1 1
12 1 1
Scod: 0
ProgressionOrder: 0
NumberOfLayers: 0
MultiCompTransform: 0
DecompositionLevels: 0
CodeblockWidth: 0
CodeblockHeight: 0
CodeblockStyle: 0
Transformation: 0
Precincts: 0
precinct dimensions:
Sqcd: 0
SPqcd: 0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000
Frame: 000000, 1280344 bytes
Frame: 000001, 1279704 bytes
Frame: 000002, 1276600 bytes
Frame: 000003, 1281528 bytes
Frame: 000004, 1277496 bytes
Frame: 000005, 1279368 bytes
Frame: 000006, 1279672 bytes
Frame: 000007, 1278264 bytes
Frame: 000008, 1275080 bytes
Frame: 000009, 1278264 bytes
Frame: 000010, 1275000 bytes
Frame: 000011, 1281576 bytes
** Version cryptographique **
asdcp-test -v -x ./output/image \
-k adcafe5aca5f6bfd87ca381245acfeac \
jp2k_enc_video.mxf
** Type d'output **
JPEG-2000 Code Stream Bitmap data
====== Encoding J2C to DivX ======
# for file in *.j2c; do echo $file; convert ${file} ${file}.jpg; done;
# mencoder mf://0001*.jpg -mf fps=24 -ovc xvid -ffourcc DIVX -xvidencopts pass=1:vhq=4:autoaspect -vf scale=2048:857 -o movie.avi
====== Encoding/Decoding Base64 Package =====
$ openssl base64 -in package -out package.enc
$ openssl enc -d -base64 -in package.enc -out package
====== Packaging ======
Wrappé en base64
===== getdcp =====
Partie de code en Perl pour décrypter un MXF si on a le KDM et le certificat privé
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
KAAA
===== DKDM Dewrap =====
def unwrap_dkdm(dkdm_file):
print("* Opening DKDM %s" % dkdm_file)
with open(dkdm_file, "r") as file:
dkdm = xmltodict.parse(file.read(), dict_constructor=dict, process_namespaces=False, xml_attribs=True)
print("* Opening Private Key %s" % self.args.private_key)
with open(self.args.private_key, "r") as file:
private_key = file.read()
privkey = RSA.importKey(private_key, passphrase=base64.b64decode("VGhlIFRydXRoIElzIE91dCBUaGVyZS4=")) # tiny-tiny-obfuscation
decipher = PKCS1_OAEP.new(privkey)
# DCinemaSecurityMessage > AuthenticatedPublic > RequiredExtensions > KDMRequiredExtensions > KeyIdList > TypedKeyId[] > KeyId
print("\n* Parsing DCinemaSecurityMessage > AuthenticatedPublic > RequiredExtensions > KDMRequiredExtensions > KeyIdList > TypedKeyId > KeyId")
for index, key in enumerate(dkdm['DCinemaSecurityMessage']['AuthenticatedPublic']['RequiredExtensions']['KDMRequiredExtensions']['KeyIdList']['TypedKeyId']):
uuid = key['KeyId'].split("urn:uuid:")[1]
print("[%02d] Indexing %s - %s" % (index, uuid, key['KeyType']['#text']))
# DCinemaSecurityMessage > AuthenticatedPrivate > enc:EncryptedKey[] > enc:CipherData
print("\n* Parsing DCinemaSecurityMessage > AuthenticatedPrivate > enc:EncryptedKey > enc:CipherData")
for index, key in enumerate(dkdm['DCinemaSecurityMessage']['AuthenticatedPrivate']['enc:EncryptedKey']):
cipher_base64 = key['enc:CipherData']['enc:CipherValue']
cipher_text = base64.b64decode(cipher_base64)
plain_text = decipher.decrypt(cipher_text)
print("* Structure ID :", binascii.hexlify(plain_text[0:0+16]).decode('utf-8'))
print("* Certificate ThumbPrint :", binascii.hexlify(plain_text[16:16+20]).decode('utf-8'))
print("* CPL Id :", binascii.hexlify(plain_text[36:36+16]).decode('utf-8'))
print("* KeyType :", plain_text[52:52+4].decode('utf-8'))
print("* KeyId :", binascii.hexlify(plain_text[56:56+16]).decode('utf-8'))
print("* Date Not Valid Before :", plain_text[72:72+25].decode('utf-8'))
print("* Date Not Valid After :", plain_text[97:97+25].decode('utf-8'))
print("* AES Key :", binascii.hexlify(plain_text[122:122+16]).decode('utf-8'))
print("")