FINALLY decoded the eContent signed

This commit is contained in:
0xturboblitz
2023-07-26 23:38:22 +02:00
parent cde4c8368c
commit de23a800db
5 changed files with 928 additions and 262 deletions

2
app/.gitignore vendored
View File

@@ -64,3 +64,5 @@ yarn-error.log
# testing
/coverage
.env

View File

@@ -58,6 +58,7 @@ import org.jmrtd.lds.icao.DG14File
import org.jmrtd.lds.icao.DG1File
import org.jmrtd.lds.icao.DG2File
import org.jmrtd.lds.iso19794.FaceImageInfo
import org.json.JSONObject
import java.io.ByteArrayInputStream

859
app/scripts/r&d.ts Normal file
View File

@@ -0,0 +1,859 @@
import * as crypto from 'crypto';
// On a la donnée de base :
const dg1File = {
length: 91,
mrzInfo: {
compositeCheckDigit: '2',
dateOfBirth: '000719',
dateOfBirthCheckDigit: '1',
dateOfExpiry: '291209',
dateOfExpiryCheckDigit: '5',
documentCode: 'P',
documentNumber: '19HA34828',
documentNumberCheckDigit: '4',
documentType: 3,
gender: 'MALE',
issuingState: 'FRA',
nationality: 'FRA',
optionalData1: '<<<<<<<<<<<<<<0',
primaryIdentifier: 'TAVERNIER',
secondaryIdentifier: 'FLORENT<HUGUES<JEAN<<<<<<<<<',
},
tag: 97,
};
const mrzInfo = dg1File.mrzInfo;
// 'P<FRATAVERNIER<<FLORENT<HUGUES<JEAN<<<<<<<<<19HA348284FRA0007191M2912095<<<<<<<<<<<<<<02';
const mrz =
mrzInfo.documentCode +
'<' +
mrzInfo.issuingState +
mrzInfo.primaryIdentifier +
'<<' +
mrzInfo.secondaryIdentifier +
mrzInfo.documentNumber +
mrzInfo.documentNumberCheckDigit +
mrzInfo.nationality +
mrzInfo.dateOfBirth +
mrzInfo.dateOfBirthCheckDigit +
mrzInfo.gender.substring(0, 1) +
mrzInfo.dateOfExpiry +
mrzInfo.dateOfExpiryCheckDigit +
mrzInfo.optionalData1 +
mrzInfo.compositeCheckDigit;
console.log('mrz: ', mrz);
const mrzCharcodes = [...mrz].map(char => char.charCodeAt(0));
console.log('mrzCharcodes:', mrzCharcodes);
mrzCharcodes.unshift(88); // the length of the mrz data
mrzCharcodes.unshift(95, 31); // the MRZ_INFO_TAG
mrzCharcodes.unshift(91); // the new length of the whole array
mrzCharcodes.unshift(97); // the tag for DG1
console.log('mrzCharcodes with tags:', mrzCharcodes);
const hash = crypto.createHash('sha256');
hash.update(Buffer.from(mrzCharcodes));
const dataHash = hash.digest('hex');
console.log('dataHash:', dataHash);
// C'est bien dataHashes["1"]
const dataHashes = {
'1': [
99, 19, -77, -51, 55, 104, 45, -42, -123, 101, -23, -79, -126, 1, 37, 89,
125, -27, -117, 34, -124, -110, 28, 116, -8, -70, 63, -61, 96, -105, 26,
-41,
],
'2': [
63, -22, 106, 78, 31, 16, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67,
-23, -55, -43, 53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114,
],
'3': [
-120, -101, 87, -112, 121, 15, -104, 127, 85, 25, -102, 80, 20, 58, 51, 75,
-63, 116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124,
],
'11': [
0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110,
-57, 108, -6, 36, 21, 39, 87, 110, 102, -6, -43, -82, -125, -85, -82,
],
'12': [
-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14,
-100, -115, -128, -9, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38,
],
'13': [
91, -34, -46, -63, 63, -34, 104, 82, 36, 41, -118, -3, 70, 15, -108, -48,
-100, 45, 105, -85, -15, -61, -71, 43, -39, -94, -110, -55, -34, 89, -18,
38,
],
'14': [
76, 123, -40, 13, 52, -29, 72, -11, 59, -63, -18, -90, 103, 49, 24, -92,
-85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38,
],
};
const dataHashesAsArray = [
[
99, 19, -77, -51, 55, 104, 45, -42, -123, 101, -23, -79, -126, 1, 37, 89,
125, -27, -117, 34, -124, -110, 28, 116, -8, -70, 63, -61, 96, -105, 26,
-41,
],
[
63, -22, 106, 78, 31, 16, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67,
-23, -55, -43, 53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114,
],
[
-120, -101, 87, -112, 121, 15, -104, 127, 85, 25, -102, 80, 20, 58, 51, 75,
-63, 116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124,
],
[
0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110,
-57, 108, -6, 36, 21, 39, 87, 110, 102, -6, -43, -82, -125, -85, -82,
],
[
-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14,
-100, -115, -128, -9, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38,
],
[
91, -34, -46, -63, 63, -34, 104, 82, 36, 41, -118, -3, 70, 15, -108, -48,
-100, 45, 105, -85, -15, -61, -71, 43, -39, -94, -110, -55, -34, 89, -18,
38,
],
[
76, 123, -40, 13, 52, -29, 72, -11, 59, -63, -18, -90, 103, 49, 24, -92,
-85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38,
],
];
function concatenateHashes(hashes: Buffer[]): Buffer {
return Buffer.concat(hashes);
}
function hashData(data: Buffer): string {
const hash = crypto.createHash('sha256');
hash.update(data);
// return new Uint8Array(hash.digest().buffer);
return hash.digest('hex');
}
console.log(
'concatenateHashes(dataHashes) hash:',
hashData(concatenateHashes(dataHashesAsArray.map(hash => Buffer.from(hash)))),
);
// const concat = [
// 99, 19, -77, -51, 55, 104, 45, -42, -123, 101, -23, -79, -126, 1, 37, 89, 125,
// -27, -117, 34, -124, -110, 28, 116, -8, -70, 63, -61, 96, -105, 26, -41, 63,
// -22, 106, 78, 31, 16, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23,
// -55, -43, 53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114, -120, -101,
// 87, -112, 121, 15, -104, 127, 85, 25, -102, 80, 20, 58, 51, 75, -63, 116, -22,
// 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124, 0, -62, 104, 108,
// -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110, -57, 108, -6, 36,
// 21, 39, 87, 110, 102, -6, -43, -82, -125, -85, -82, -66, 82, -76, -21, -34,
// 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128, -9, 10,
// 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38, 91, -34, -46, -63, 63, -34,
// 104, 82, 36, 41, -118, -3, 70, 15, -108, -48, -100, 45, 105, -85, -15, -61,
// -71, 43, -39, -94, -110, -55, -34, 89, -18, 38, 76, 123, -40, 13, 52, -29, 72,
// -11, 59, -63, -18, -90, 103, 49, 24, -92, -85, -68, -62, -59, -100, -69, -7,
// 28, -58, 95, 69, 15, -74, 56, 54, 38,
// ];
// const concatHash = crypto.createHash('sha256');
// concatHash.update(Buffer.from(concat));
// const concatHashBytes = new Uint8Array(concatHash.digest().buffer);
// console.log('concatHashBytes:', concatHashBytes);
const messageDigest = [
-80, 96, 59, -43, -125, 82, 89, -8, 105, 125, 37, -79, -98, -94, -119, 43, 13,
39, 115, 6, 59, -27, 81, 110, 49, 75, -1, -72, -101, 73, 116, 86,
];
// console.log('messageDigest:', messageDigest);
// Convert signed bytes to unsigned
const unsignedBytes = messageDigest.map(b => (b < 0 ? b + 256 : b));
// Convert to a Buffer, then to hex
const messageDigestHex = Buffer.from(unsignedBytes).toString('hex');
console.log('messageDigest:', messageDigestHex);
const eContent =
'3166301506092a864886f70d01090331080606678108010101301c06092a864886f70d010905310f170d3139313231363137323233385a302f06092a864886f70d01090431220420b0603bd5835259f8697d25b19ea2892b0d2773063be5516e314bffb89b497456';
// function hexToBytes(hex: string) {
// let bytes = new Uint8Array(Math.ceil(hex.length / 2));
// for (let i = 0; i < bytes.length; i++) {
// bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
// }
// return bytes;
// }
// console.log('hexToBytes(eContent):', hexToBytes(eContent));
// const eContentUTF8 = Buffer.from(eContent, 'hex').toString('ascii');
// console.log(eContentUTF8);
// 49 : TAG
// 102 : LENGTH
// 48... : sequence
// 49, 102, 48, 21, 6, 9, 42, 134, 72, 134, 247, 13,
// 1, 9, 3, 49, 8, 6, 6, 103, 129, 8, 1, 1,
// 1, 48, 28, 6, 9, 42, 134, 72, 134, 247, 13, 1,
// 9, 5, 49, 15, 23, 13, 49, 57, 49, 50, 49, 54,
// 49, 55, 50, 50, 51, 56, 90, 48, 47, 6, 9, 42,
// 134, 72, 134, 247, 13, 1, 9, 4, 49, 34, 4, 32,
// 176, 96, 59, 213, 131, 82, 89, 248, 105, 125, 37, 177,
// 158, 162, 137, 43, 13, 39, 115, 6, 59, 229, 81, 110,
// 49, 75, 255, 184, 155, 73, 116, 86
// "1.2.840.113549.1.9.4"
// TAG, LGT, RFC_3369 TAG..., TAG, SEQUENCE...
// RFC_3369_CONTENT_TYPE_OID 48, 21, 6, 9, 42, 134, 72, 134, 247, 13, 1, 9, 3, | 49, 8, 6, 6, 103, 129, 8, 1, 1, 1,
// signing-time 48, 28, 6, 9, 42, 134, 72, 134, 247, 13, 1, 9, 5, | 49, 15, 23, 13, 49, 57, 49, 50, 49, 54, 49, 55, 50, 50, 51, 56, 90,
// RFC_3369_MESSAGE_DIGEST_OID 48, 47, 6, 9, 42, 134, 72, 134, 247, 13, 1, 9, 4, | 49, 34, 4, 32, | 176, 96, 59, 213, 131, 82, 89, 248, 105, 125, 37, 177, 158, 162, 137, 43, 13, 39, 115, 6, 59, 229, 81, 110, 49, 75, 255, 184, 155, 73, 116, 86
// Donc je veux arriver au hash suivant pour les dataHashes concaténés:
// 34, 4, 32, | 176, 96, 59, 213, 131, 82, 89, 248, 105, 125, 37, 177, 158, 162, 137, 43, 13, 39, 115, 6, 59, 229, 81, 110, 49, 75, 255, 184, 155, 73, 116, 86
// const dataHashes = {
// '1': [
// 99, 19, -77, -51, 55, 104, 45, -42, -123, 101, -23, -79, -126, 1, 37, 89,
// 125, -27, -117, 34, -124, -110, 28, 116, -8, -70, 63, -61, 96, -105, 26,
// -41,
// ],
// '2': [
// 63, -22, 106, 78, 31, 16, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67,
// -23, -55, -43, 53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114,
// ],
// '3': [
// -120, -101, 87, -112, 121, 15, -104, 127, 85, 25, -102, 80, 20, 58, 51, 75,
// -63, 116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124,
// ],
// '11': [
// 0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110,
// -57, 108, -6, 36, 21, 39, 87, 110, 102, -6, -43, -82, -125, -85, -82,
// ],
// '12': [
// -66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14,
// -100, -115, -128, -9, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38,
// ],
// '13': [
// 91, -34, -46, -63, 63, -34, 104, 82, 36, 41, -118, -3, 70, 15, -108, -48,
// -100, 45, 105, -85, -15, -61, -71, 43, -39, -94, -110, -55, -34, 89, -18,
// 38,
// ],
// '14': [
// 76, 123, -40, 13, 52, -29, 72, -11, 59, -63, -18, -90, 103, 49, 24, -92,
// -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38,
// ],
// };
// ContentInfo encapContentInfo = signedData.getEncapContentInfo();
// DEROctetString eContent = (DEROctetString)encapContentInfo.getContent();
const signedData = {
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
body: [42, -122, 72, -122, -9, 13, 1, 9, 3],
identifier: '1.2.840.113549.1.9.3',
},
{
bodyLength: -1,
elements: [
{body: [103, -127, 8, 1, 1, 1], identifier: '2.23.136.1.1.1'},
],
isSorted: true,
},
],
},
{
bodyLength: -1,
elements: [
{
body: [42, -122, 72, -122, -9, 13, 1, 9, 5],
identifier: '1.2.840.113549.1.9.5',
},
{
bodyLength: -1,
elements: [
{time: [49, 57, 49, 50, 49, 54, 49, 55, 50, 50, 51, 56, 90]},
],
isSorted: true,
},
],
},
{
bodyLength: -1,
elements: [
{
body: [42, -122, 72, -122, -9, 13, 1, 9, 4],
identifier: '1.2.840.113549.1.9.4',
},
{
bodyLength: -1,
elements: [
{
string: [
-80, 96, 59, -43, -125, 82, 89, -8, 105, 125, 37, -79, -98, -94,
-119, 43, 13, 39, 115, 6, 59, -27, 81, 110, 49, 75, -1, -72,
-101, 73, 116, 86,
],
},
],
isSorted: true,
},
],
},
],
isSorted: false,
};
// Convert the byte arrays into hex strings, and store them in an array in the correct order
const hashHexStrings = Object.keys(dataHashes)
.sort()
.map(key => {
const byteArray = dataHashes[key as keyof typeof dataHashes];
// Convert signed bytes to unsigned, then to hex string
const hexString = byteArray
.map(b => (b < 0 ? b + 256 : b))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
return hexString;
});
// Concatenate the hex strings
const concatenatedHashesHex = hashHexStrings.join('');
// Hash the concatenated hashes to get the message digest in hex
const messageDigestHex2 = hashDataHex(concatenatedHashesHex);
console.log('messageDigestHex2:', messageDigestHex2);
// Function to hash hex data
function hashDataHex(dataHex: string): string {
const hash = crypto.createHash('sha256');
hash.update(dataHex, 'hex');
return hash.digest('hex');
}
// SignedAttributesSet:
// [1.2.840.113549.1.9.3, [2.23.136.1.1.1]],
// [1.2.840.113549.1.9.5, [191216172238Z]]
// [1.2.840.113549.1.9.4, [#b0603bd5835259f8697d25b19ea2892b0d2773063be5516e314bffb89b497456]]
// ContentInfo contentInfo = signedData.getEncapContentInfo();
// et contentBytes
// C'est le champ contentInfo de signedData
const contentBytes = [
48, -126, 1, 37, 2, 1, 0, 48, 11, 6, 9, 96, -122, 72, 1, 101, 3, 4, 2, 1, 48,
-126, 1, 17, 48, 37, 2, 1, 1, 4, 32, 99, 19, -77, -51, 55, 104, 45, -42, -123,
101, -23, -79, -126, 1, 37, 89, 125, -27, -117, 34, -124, -110, 28, 116, -8,
-70, 63, -61, 96, -105, 26, -41, 48, 37, 2, 1, 2, 4, 32, 63, -22, 106, 78, 31,
16, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -43, 53, 4,
47, -67, -55, -123, 6, 121, 34, -125, 64, -114, 48, 37, 2, 1, 3, 4, 32, -120,
-101, 87, -112, 121, 15, -104, 127, 85, 25, -102, 80, 20, 58, 51, 75, -63,
116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124, 48, 37, 2,
1, 11, 4, 32, 0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87,
17, 89, 110, -57, 108, -6, 36, 21, 39, 87, 110, 102, -6, -43, -82, -125, -85,
-82, 48, 37, 2, 1, 12, 4, 32, -66, 82, -76, -21, -34, 33, 79, 50, -104, -120,
-114, 35, 116, -32, 6, -14, -100, -115, -128, -9, 10, 61, 98, 86, -8, 45, -49,
-46, 90, -24, -81, 38, 48, 37, 2, 1, 13, 4, 32, 91, -34, -46, -63, 63, -34,
104, 82, 36, 41, -118, -3, 70, 15, -108, -48, -100, 45, 105, -85, -15, -61,
-71, 43, -39, -94, -110, -55, -34, 89, -18, 38, 48, 37, 2, 1, 14, 4, 32, 76,
123, -40, 13, 52, -29, 72, -11, 59, -63, -18, -90, 103, 49, 24, -92, -85, -68,
-62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38,
];
// let's hash contentBytes
const contentBytesHash = crypto.createHash('sha256');
contentBytesHash.update(Buffer.from(contentBytes));
const concatHashBytes = new Uint8Array(contentBytesHash.digest().buffer);
console.log('concatHashBytes', concatHashBytes);
// AttributesBytes : ça c'est précisément le eContent entier
// [49, 102, 48, 21, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 3, 49, 8, 6, 6, 103, -127, 8, 1, 1, 1, 48, 28, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 5, 49, 15, 23, 13, 49, 57, 49, 50, 49, 54, 49, 55, 50, 50, 51, 56, 90, 48, 47, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 4, 49, 34, 4, 32, -80, 96, 59, -43, -125, 82, 89, -8, 105, 125, 37, -79, -98, -94, -119, 43, 13, 39, 115, 6, 59, -27, 81, 110, 49, 75, -1, -72, -101, 73, 116, 86]
// storedDigestedContent = computedDigestedContent = ça :
// [-80, 96, 59, -43, -125, 82, 89, -8, 105, 125, 37, -79, -98, -94, -119, 43, 13, 39, 115, 6, 59, -27, 81, 110, 49, 75, -1, -72, -101, 73, 116, 86]
// Premier mystère résolu : le truc est bien le contentBytes hashé
// 48 : SEQUENCE
// -126, 1, 37 : LENGTH (293 bytes long (1*256 + 37 = 293))
// 2, 1, 0 : VERSION of the ASN.1 structure, which is 0.
// 48 : SEQUENCE
// 11 : LENGTH (11 bytes long)
// 6 : ASN.1 tag for OBJECT IDENTIFIER, or OID.
// 9 : the OID is 9 bytes long.
// 96, -122, 72, 1, 101, 3, 4, 2, 1 : the OID for SHA-256
// 48 : SEQUENCE
// -126, 1, 17, : LENGTH (273 bytes long)
// DATAHASHES :
// 48, 37, 2, 1, 1, 4, 32,
// 99, 19, -77, -51, 55, 104, 45, -42, -123, 101, -23, -79, -126, 1, 37, 89, 125, -27, -117, 34, -124, -110, 28, 116, -8, -70, 63, -61, 96, -105, 26, -41,
// 48, 37, 2, 1, 2, 4, 32,
// 63, -22, 106, 78, 31, 16, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -43, 53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114,
// 48, 37, 2, 1, 3, 4, 32,
// -120, -101, 87, -112, 121, 15, -104, 127, 85, 25, -102, 80, 20, 58, 51, 75, -63, 116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124,
// 48, 37, 2, 1, 11, 4, 32,
// 0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110, -57, 108, -6, 36, 21, 39, 87, 110, 102, -6, -43, -82, -125, -85, -82,
// 48, 37, 2, 1, 12, 4, 32,
// -66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128, -9, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38,
// 48, 37, 2, 1, 13, 4, 32,
// 91, -34, -46, -63, 63, -34, 104, 82, 36, 41, -118, -3, 70, 15, -108, -48, -100, 45, 105, -85, -15, -61, -71, 43, -39, -94, -110, -55, -34, 89, -18, 38,
// 48, 37, 2, 1, 14, 4, 32,
// 76, 123, -40, 13, 52, -29, 72, -11, 59, -63, -18, -90, 103, 49, 24, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38,
const SignedData = {
certificates: {
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
explicit: true,
obj: {
bytes: [2],
start: 0,
},
tagNo: 0,
},
{
bytes: [
17, 33, -111, 26, -11, -11, 51, -30, -25, -93, 97, 37, -92,
106, -34, -23, 36, 61,
],
start: 0,
},
{
bodyLength: -1,
elements: [
{
body: [42, -122, 72, -122, -9, 13, 1, 1, 11],
identifier: '1.2.840.113549.1.1.11',
},
{},
],
},
{
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
body: [85, 4, 6],
identifier: '2.5.4.6',
},
{
string: [70, 82],
},
],
},
],
isSorted: true,
},
{
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
body: [85, 4, 10],
identifier: '2.5.4.10',
},
{
string: [71, 111, 117, 118],
},
],
},
],
isSorted: true,
},
{
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
body: [85, 4, 3],
identifier: '2.5.4.3',
},
{
string: [
67, 83, 67, 65, 45, 70, 82, 65, 78, 67, 69,
],
},
],
},
],
isSorted: true,
},
],
},
{
bodyLength: -1,
elements: [
{
time: [49, 57, 49, 49, 48, 53, 49, 52, 50, 57, 48, 55, 90],
},
{
time: [51, 48, 48, 50, 48, 53, 49, 52, 50, 57, 48, 55, 90],
},
],
},
{
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
body: [85, 4, 6],
identifier: '2.5.4.6',
},
{
string: [70, 82],
},
],
},
],
isSorted: true,
},
{
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
body: [85, 4, 10],
identifier: '2.5.4.10',
},
{
string: [71, 111, 117, 118],
},
],
},
],
isSorted: true,
},
{
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
body: [85, 4, 11],
identifier: '2.5.4.11',
},
{
string: [
68, 111, 99, 117, 109, 101, 110, 116, 32, 83, 105,
103, 110, 101, 114,
],
},
],
},
],
isSorted: true,
},
{
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
body: [85, 4, 3],
identifier: '2.5.4.3',
},
{
string: [72, 83, 77, 95, 68, 83, 95, 50],
},
],
},
],
isSorted: true,
},
{
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
body: [85, 4, 5],
identifier: '2.5.4.5',
},
{
string: [
50, 48, 49, 57, 49, 49, 48, 53, 49, 52, 50, 57,
48, 50, 48,
],
},
],
},
],
isSorted: true,
},
],
},
{
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
body: [42, -122, 72, -122, -9, 13, 1, 1, 1],
identifier: '1.2.840.113549.1.1.1',
},
{},
],
},
{
data: [
48, -126, 1, 10, 2, -126, 1, 1, 0, -33, 17, -70, 6, -41,
-109, 122, 5, -98, -116, -25, -111, 106, -80, -5, 11, 9,
74, -101, -98, -49, -104, -23, 126, -38, 104, 52, -94, 48,
117, -14, 3, 0, 114, -93, -57, -122, -113, -123, 4, 90,
-14, -84, -75, -11, -62, -66, -33, 108, 37, 97, 77, -103,
35, 43, -104, -69, 69, 110, 95, -116, -29, 33, 72, -120,
47, 34, -127, 83, 122, -57, -86, -128, -28, -51, -73, -98,
12, -33, 70, 39, -51, 8, -38, 50, -50, 38, 62, -11, 74,
38, -62, -54, 52, -109, -15, -48, 45, -97, -85, -51, -119,
-107, 32, 88, -53, 0, -123, -6, 53, 107, 19, -7, -30, -52,
30, -100, -92, -12, 118, 120, -36, 73, 18, -99, 85, 83,
27, -46, -127, 125, -44, 54, -43, -82, -9, 120, -44, -44,
57, -46, -42, 89, -80, -49, -99, 88, -18, -1, 67, -50, 44,
-1, 38, -43, -58, 109, 35, 22, 65, 35, -4, -100, 62, 108,
-44, -112, 46, -99, 123, 84, -39, 80, -101, 3, -7, 93,
-21, -4, 63, -79, 94, -9, -76, 88, -84, 100, -94, -58,
-30, 107, -16, 16, 69, 30, -1, 103, -19, -121, -10, -54,
122, -108, 109, -41, -84, -122, -34, -94, 86, 108, -67,
-55, -86, 14, 60, -70, -83, -97, 94, -44, -74, -120, 108,
-48, -113, 107, -81, 20, -121, -75, -113, 107, -93, 48,
117, -106, -125, -106, -62, 22, -17, 101, -80, -21, 73,
-58, -105, -124, 100, -36, -34, -103, -7, -87, -95, 2, 3,
1, 0, 1,
],
padBits: 0,
},
],
},
{
explicit: true,
obj: {
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
body: [85, 29, 32],
identifier: '2.5.29.32',
},
{
string: [
48, 55, 48, 53, 6, 10, 42, -127, 122, 1, -127, 31,
1, 1, 1, 2, 48, 39, 48, 37, 6, 8, 43, 6, 1, 5, 5, 7,
2, 1, 22, 25, 104, 116, 116, 112, 115, 58, 47, 47,
97, 110, 116, 115, 46, 103, 111, 117, 118, 46, 102,
114, 47, 99, 115, 99, 97,
],
},
],
},
{
bodyLength: -1,
elements: [
{
body: [85, 29, 15],
identifier: '2.5.29.15',
},
{
value: -1,
},
{
string: [3, 2, 7, -128],
},
],
},
{
bodyLength: -1,
elements: [
{
body: [85, 29, 16],
identifier: '2.5.29.16',
},
{
string: [
48, 34, -128, 15, 50, 48, 49, 57, 49, 49, 48, 53,
49, 52, 50, 57, 48, 55, 90, -127, 15, 50, 48, 50,
48, 48, 50, 48, 53, 49, 52, 50, 57, 48, 55, 90,
],
},
],
},
{
bodyLength: -1,
elements: [
{
body: [85, 29, 17],
identifier: '2.5.29.17',
},
{
string: [
48, 27, -122, 25, 104, 116, 116, 112, 115, 58, 47,
47, 97, 110, 116, 115, 46, 103, 111, 117, 118, 46,
102, 114, 47, 99, 115, 99, 97,
],
},
],
},
{
bodyLength: -1,
elements: [
{
body: [85, 29, 18],
identifier: '2.5.29.18',
},
{
string: [
48, 45, -122, 25, 104, 116, 116, 112, 115, 58, 47,
47, 97, 110, 116, 115, 46, 103, 111, 117, 118, 46,
102, 114, 47, 99, 115, 99, 97, -92, 16, 48, 14, 49,
12, 48, 10, 6, 3, 85, 4, 7, 19, 3, 70, 82, 65,
],
},
],
},
{
bodyLength: -1,
elements: [
{
body: [85, 29, 31],
identifier: '2.5.29.31',
},
{
string: [
48, 36, 48, 34, -96, 32, -96, 30, -122, 28, 104,
116, 116, 112, 58, 47, 47, 97, 110, 116, 115, 46,
103, 111, 117, 118, 46, 102, 114, 47, 99, 115, 99,
97, 95, 99, 114, 108,
],
},
],
},
{
bodyLength: -1,
elements: [
{
body: [103, -127, 8, 1, 1, 6, 2],
identifier: '2.23.136.1.1.6.2',
},
{
string: [
48, 12, 2, 1, 0, 49, 7, 19, 1, 80, 19, 2, 73, 82,
],
},
],
},
{
bodyLength: -1,
elements: [
{
body: [85, 29, 14],
identifier: '2.5.29.14',
},
{
string: [
4, 20, 66, -31, -84, 81, 17, -85, -80, 4, 76, 116,
-104, -95, 29, -98, -44, 101, -47, 31, 41, -5,
],
},
],
},
{
bodyLength: -1,
elements: [
{
body: [85, 29, 35],
identifier: '2.5.29.35',
},
{
string: [
48, 22, -128, 20, 15, -52, 50, 124, -66, 4, -9, 41,
5, -34, 37, 14, -7, -106, -100, -91, 28, -120, 38,
124, -33, 27, 100, -92, -22, 107, 90, 76, 46, 98,
-42, -60, -48, -16, -67, 62, 56, -77, -42, -17, 13,
-107, 113, 82, -18, 77, 114, 115, -57, -101, 40,
-15, 85, 120, -40, 17, 123, -81, -49, 114, -81, 27,
-27, 33, -47, -61, 65, -37, -28, 111, -39, 15, -33,
98, -21, 83, -13, -32, -33, -80, 27, 104, 102, 66,
-11, -103, 28, 12, 7, 117, 90, 95, 29, 54, 122, -28,
-108, -28, -114, 103, -47, -51, -78, -109, -31, 13,
-111, -115,
],
padBits: 0,
},
],
},
],
isSorted: true,
},
certsBer: false,
contentInfo: {
content: {
string: [
48, -126, 1, 37, 2, 1, 0, 48, 11, 6, 9, 96, -122, 72, 1,
101, 3, 4, 2, 1, 48, -126, 1, 17, 48, 37, 2, 1, 1, 4, 32,
99, 19, -77, -51, 55, 104, 45, -42, -123, 101, -23, -79,
-126, 1, 37, 89, 125, -27, -117, 34, -124, -110, 28, 116,
-8, -70, 63, -61, 96, -105, 26, -41, 48, 37, 2, 1, 2, 4,
32, 63, -22, 106, 78, 31, 16, 114, -119, -19, 17, 92, 71,
-122, 47, 62, 78, -67, -23, -55, -43, 53, 4, 47, -67, -55,
-123, 6, 121, 34, -125, 64, -114, 48, 37, 2, 1,
],
},
},
},
],
},
],
},
],
},
};

View File

@@ -43,26 +43,6 @@ const mrz =
mrzInfo.optionalData1 +
mrzInfo.compositeCheckDigit;
console.log('mrz: ', mrz);
const mrzCharcodes = [...mrz].map(char => char.charCodeAt(0));
console.log('mrzCharcodes:', mrzCharcodes);
mrzCharcodes.unshift(88); // the length of the mrz data
mrzCharcodes.unshift(95, 31); // the MRZ_INFO_TAG
mrzCharcodes.unshift(91); // the new length of the whole array
mrzCharcodes.unshift(97); // the tag for DG1
console.log('mrzCharcodes with tags:', mrzCharcodes);
const hash = crypto.createHash('sha256');
hash.update(Buffer.from(mrzCharcodes));
const dataHash = hash.digest('hex');
console.log('dataHash:', dataHash);
// C'est bien dataHashes["1"]
const dataHashes = {
'1': [
99, 19, -77, -51, 55, 104, 45, -42, -123, 101, -23, -79, -126, 1, 37, 89,
@@ -96,252 +76,76 @@ const dataHashes = {
],
};
const dataHashesAsArray = [
[
99, 19, -77, -51, 55, 104, 45, -42, -123, 101, -23, -79, -126, 1, 37, 89,
125, -27, -117, 34, -124, -110, 28, 116, -8, -70, 63, -61, 96, -105, 26,
-41,
],
[
63, -22, 106, 78, 31, 16, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67,
-23, -55, -43, 53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114,
],
[
-120, -101, 87, -112, 121, 15, -104, 127, 85, 25, -102, 80, 20, 58, 51, 75,
-63, 116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124,
],
[
0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110,
-57, 108, -6, 36, 21, 39, 87, 110, 102, -6, -43, -82, -125, -85, -82,
],
[
-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14,
-100, -115, -128, -9, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38,
],
[
91, -34, -46, -63, 63, -34, 104, 82, 36, 41, -118, -3, 70, 15, -108, -48,
-100, 45, 105, -85, -15, -61, -71, 43, -39, -94, -110, -55, -34, 89, -18,
38,
],
[
76, 123, -40, 13, 52, -29, 72, -11, 59, -63, -18, -90, 103, 49, 24, -92,
-85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38,
],
const contentBytes = [
48, -126, 1, 37, 2, 1, 0, 48, 11, 6, 9, 96, -122, 72, 1, 101, 3, 4, 2, 1, 48,
-126, 1, 17, 48, 37, 2, 1, 1, 4, 32, 99, 19, -77, -51, 55, 104, 45, -42, -123,
101, -23, -79, -126, 1, 37, 89, 125, -27, -117, 34, -124, -110, 28, 116, -8,
-70, 63, -61, 96, -105, 26, -41, 48, 37, 2, 1, 2, 4, 32, 63, -22, 106, 78, 31,
16, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -43, 53, 4,
47, -67, -55, -123, 6, 121, 34, -125, 64, -114, 48, 37, 2, 1, 3, 4, 32, -120,
-101, 87, -112, 121, 15, -104, 127, 85, 25, -102, 80, 20, 58, 51, 75, -63,
116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124, 48, 37, 2,
1, 11, 4, 32, 0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87,
17, 89, 110, -57, 108, -6, 36, 21, 39, 87, 110, 102, -6, -43, -82, -125, -85,
-82, 48, 37, 2, 1, 12, 4, 32, -66, 82, -76, -21, -34, 33, 79, 50, -104, -120,
-114, 35, 116, -32, 6, -14, -100, -115, -128, -9, 10, 61, 98, 86, -8, 45, -49,
-46, 90, -24, -81, 38, 48, 37, 2, 1, 13, 4, 32, 91, -34, -46, -63, 63, -34,
104, 82, 36, 41, -118, -3, 70, 15, -108, -48, -100, 45, 105, -85, -15, -61,
-71, 43, -39, -94, -110, -55, -34, 89, -18, 38, 48, 37, 2, 1, 14, 4, 32, 76,
123, -40, 13, 52, -29, 72, -11, 59, -63, -18, -90, 103, 49, 24, -92, -85, -68,
-62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38,
];
function concatenateHashes(hashes: Buffer[]): Buffer {
return Buffer.concat(hashes);
}
function hashData(data: Buffer): string {
const hash = crypto.createHash('sha256');
hash.update(data);
// return new Uint8Array(hash.digest().buffer);
return hash.digest('hex');
}
// Transforms the dataHashes object into an array of arrays
const dataHashesAsArray = Object.keys(dataHashes)
.map(key => {
const dataHash = dataHashes[key as keyof typeof dataHashes];
return [Number(key), dataHash];
})
.sort((a, b) => (a[0] as number) - (b[0] as number));
console.log(
'concatenateHashes(dataHashes) hash:',
hashData(concatenateHashes(dataHashesAsArray.map(hash => Buffer.from(hash)))),
console.log('dataHashesAsArray:', dataHashesAsArray);
console.log('mrz: ', mrz);
const mrzCharcodes = [...mrz].map(char => char.charCodeAt(0));
console.log('mrzCharcodes:', mrzCharcodes);
mrzCharcodes.unshift(88); // the length of the mrz data
mrzCharcodes.unshift(95, 31); // the MRZ_INFO_TAG
mrzCharcodes.unshift(91); // the new length of the whole array
mrzCharcodes.unshift(97); // the tag for DG1
console.log('mrzCharcodes with tags:', mrzCharcodes);
const hash = crypto.createHash('sha256');
hash.update(Buffer.from(mrzCharcodes));
const mrzHash = Array.from(hash.digest()).map(x => (x < 128 ? x : x - 256));
// Ça correspond bien :
console.log('mrzHash:', mrzHash);
console.log('dataHashes["1"]:', dataHashes['1']);
// Let's replace the first array with the MRZ hash
dataHashesAsArray.shift();
dataHashesAsArray.unshift([1, mrzHash]);
// Concaténons les dataHashes :
const concatenatedDataHashes: number[] = [].concat(
...dataHashesAsArray.map((dataHash: any) => {
dataHash[1].unshift(...[48, 37, 2, 1, dataHash[0], 4, 32]);
return dataHash[1];
}),
);
// const concat = [
// 99, 19, -77, -51, 55, 104, 45, -42, -123, 101, -23, -79, -126, 1, 37, 89, 125,
// -27, -117, 34, -124, -110, 28, 116, -8, -70, 63, -61, 96, -105, 26, -41, 63,
// -22, 106, 78, 31, 16, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23,
// -55, -43, 53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114, -120, -101,
// 87, -112, 121, 15, -104, 127, 85, 25, -102, 80, 20, 58, 51, 75, -63, 116, -22,
// 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124, 0, -62, 104, 108,
// -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110, -57, 108, -6, 36,
// 21, 39, 87, 110, 102, -6, -43, -82, -125, -85, -82, -66, 82, -76, -21, -34,
// 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128, -9, 10,
// 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38, 91, -34, -46, -63, 63, -34,
// 104, 82, 36, 41, -118, -3, 70, 15, -108, -48, -100, 45, 105, -85, -15, -61,
// -71, 43, -39, -94, -110, -55, -34, 89, -18, 38, 76, 123, -40, 13, 52, -29, 72,
// -11, 59, -63, -18, -90, 103, 49, 24, -92, -85, -68, -62, -59, -100, -69, -7,
// 28, -58, 95, 69, 15, -74, 56, 54, 38,
// ];
// const concatHash = crypto.createHash('sha256');
// concatHash.update(Buffer.from(concat));
// const concatHashBytes = new Uint8Array(concatHash.digest().buffer);
// console.log('concatHashBytes:', concatHashBytes);
const messageDigest = [
-80, 96, 59, -43, -125, 82, 89, -8, 105, 125, 37, -79, -98, -94, -119, 43, 13,
39, 115, 6, 59, -27, 81, 110, 49, 75, -1, -72, -101, 73, 116, 86,
];
// console.log('messageDigest:', messageDigest);
// Convert signed bytes to unsigned
const unsignedBytes = messageDigest.map(b => (b < 0 ? b + 256 : b));
// Convert to a Buffer, then to hex
const messageDigestHex = Buffer.from(unsignedBytes).toString('hex');
console.log('messageDigest:', messageDigestHex);
// const eContent =
// '3166301506092a864886f70d01090331080606678108010101301c06092a864886f70d010905310f170d3139313231363137323233385a302f06092a864886f70d01090431220420b0603bd5835259f8697d25b19ea2892b0d2773063be5516e314bffb89b497456';
// function hexToBytes(hex: string) {
// let bytes = new Uint8Array(Math.ceil(hex.length / 2));
// for (let i = 0; i < bytes.length; i++) {
// bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
// }
// return bytes;
// }
// console.log('hexToBytes(eContent):', hexToBytes(eContent));
// const eContentUTF8 = Buffer.from(eContent, 'hex').toString('ascii');
// console.log(eContentUTF8);
// 49 : TAG
// 102 : LENGTH
// 48... : sequence
// 49, 102, 48, 21, 6, 9, 42, 134, 72, 134, 247, 13,
// 1, 9, 3, 49, 8, 6, 6, 103, 129, 8, 1, 1,
// 1, 48, 28, 6, 9, 42, 134, 72, 134, 247, 13, 1,
// 9, 5, 49, 15, 23, 13, 49, 57, 49, 50, 49, 54,
// 49, 55, 50, 50, 51, 56, 90, 48, 47, 6, 9, 42,
// 134, 72, 134, 247, 13, 1, 9, 4, 49, 34, 4, 32,
// 176, 96, 59, 213, 131, 82, 89, 248, 105, 125, 37, 177,
// 158, 162, 137, 43, 13, 39, 115, 6, 59, 229, 81, 110,
// 49, 75, 255, 184, 155, 73, 116, 86
// "1.2.840.113549.1.9.4"
// TAG, LGT, RFC_3369 TAG..., TAG, SEQUENCE...
// RFC_3369_CONTENT_TYPE_OID 48, 21, 6, 9, 42, 134, 72, 134, 247, 13, 1, 9, 3, | 49, 8, 6, 6, 103, 129, 8, 1, 1, 1,
// signing-time 48, 28, 6, 9, 42, 134, 72, 134, 247, 13, 1, 9, 5, | 49, 15, 23, 13, 49, 57, 49, 50, 49, 54, 49, 55, 50, 50, 51, 56, 90,
// RFC_3369_MESSAGE_DIGEST_OID 48, 47, 6, 9, 42, 134, 72, 134, 247, 13, 1, 9, 4, | 49, 34, 4, 32, | 176, 96, 59, 213, 131, 82, 89, 248, 105, 125, 37, 177, 158, 162, 137, 43, 13, 39, 115, 6, 59, 229, 81, 110, 49, 75, 255, 184, 155, 73, 116, 86
// Donc je veux arriver au hash suivant pour les dataHashes concaténés:
// 34, 4, 32, | 176, 96, 59, 213, 131, 82, 89, 248, 105, 125, 37, 177, 158, 162, 137, 43, 13, 39, 115, 6, 59, 229, 81, 110, 49, 75, 255, 184, 155, 73, 116, 86
// const dataHashes = {
// '1': [
// 99, 19, -77, -51, 55, 104, 45, -42, -123, 101, -23, -79, -126, 1, 37, 89,
// 125, -27, -117, 34, -124, -110, 28, 116, -8, -70, 63, -61, 96, -105, 26,
// -41,
// ],
// '2': [
// 63, -22, 106, 78, 31, 16, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67,
// -23, -55, -43, 53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114,
// ],
// '3': [
// -120, -101, 87, -112, 121, 15, -104, 127, 85, 25, -102, 80, 20, 58, 51, 75,
// -63, 116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124,
// ],
// '11': [
// 0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110,
// -57, 108, -6, 36, 21, 39, 87, 110, 102, -6, -43, -82, -125, -85, -82,
// ],
// '12': [
// -66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14,
// -100, -115, -128, -9, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38,
// ],
// '13': [
// 91, -34, -46, -63, 63, -34, 104, 82, 36, 41, -118, -3, 70, 15, -108, -48,
// -100, 45, 105, -85, -15, -61, -71, 43, -39, -94, -110, -55, -34, 89, -18,
// 38,
// ],
// '14': [
// 76, 123, -40, 13, 52, -29, 72, -11, 59, -63, -18, -90, 103, 49, 24, -92,
// -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38,
// ],
// };
// ContentInfo encapContentInfo = signedData.getEncapContentInfo();
// DEROctetString eContent = (DEROctetString)encapContentInfo.getContent();
const signedData = {
bodyLength: -1,
elements: [
{
bodyLength: -1,
elements: [
{
body: [42, -122, 72, -122, -9, 13, 1, 9, 3],
identifier: '1.2.840.113549.1.9.3',
},
{
bodyLength: -1,
elements: [
{body: [103, -127, 8, 1, 1, 1], identifier: '2.23.136.1.1.1'},
],
isSorted: true,
},
],
},
{
bodyLength: -1,
elements: [
{
body: [42, -122, 72, -122, -9, 13, 1, 9, 5],
identifier: '1.2.840.113549.1.9.5',
},
{
bodyLength: -1,
elements: [
{time: [49, 57, 49, 50, 49, 54, 49, 55, 50, 50, 51, 56, 90]},
],
isSorted: true,
},
],
},
{
bodyLength: -1,
elements: [
{
body: [42, -122, 72, -122, -9, 13, 1, 9, 4],
identifier: '1.2.840.113549.1.9.4',
},
{
bodyLength: -1,
elements: [
{
string: [
-80, 96, 59, -43, -125, 82, 89, -8, 105, 125, 37, -79, -98, -94,
-119, 43, 13, 39, 115, 6, 59, -27, 81, 110, 49, 75, -1, -72,
-101, 73, 116, 86,
],
},
],
isSorted: true,
},
],
},
// Starting sequence. Should be the same for everybody, but not sure
concatenatedDataHashes.unshift(
...[
48, -126, 1, 37, 2, 1, 0, 48, 11, 6, 9, 96, -122, 72, 1, 101, 3, 4, 2, 1,
48, -126, 1, 17,
],
isSorted: false,
};
);
// Convert the byte arrays into hex strings, and store them in an array in the correct order
const hashHexStrings = Object.keys(dataHashes)
.sort()
.map(key => {
const byteArray = dataHashes[key as keyof typeof dataHashes];
// Convert signed bytes to unsigned, then to hex string
const hexString = byteArray
.map(b => (b < 0 ? b + 256 : b))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
return hexString;
});
// Concatenate the hex strings
const concatenatedHashesHex = hashHexStrings.join('');
// Hash the concatenated hashes to get the message digest in hex
const messageDigestHex2 = hashDataHex(concatenatedHashesHex);
console.log('messageDigestHex2:', messageDigestHex2);
// Function to hash hex data
function hashDataHex(dataHex: string): string {
const hash = crypto.createHash('sha256');
hash.update(dataHex, 'hex');
return hash.digest('hex');
}
// They are equal !
console.log('concatenatedDataHashes', concatenatedDataHashes);
console.log('contentBytes', contentBytes);