mirror of
https://github.com/selfxyz/self.git
synced 2026-04-05 03:00:53 -04:00
refactor circuits repo, add sha1 and rsapss dsc verification in circuits
This commit is contained in:
File diff suppressed because one or more lines are too long
9
common/scripts/README.md
Normal file
9
common/scripts/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# How to generate mock passport data based on your real data?
|
||||
|
||||
- Build the app and scan your passport to log your passport data.
|
||||
- Copy one of the files of this folder and paste your passport data.
|
||||
- Adapt the `verify` function to verify it. Once this is done, adapt the `genMockPassportData` to generate a mock one.
|
||||
- Once the mock passport data generated is verified correctly by the same `verify` function that verifies yours, you're all set!
|
||||
- Run the script to generate a mock passport data and add it to `common/src/utils/mockPassportData.ts`
|
||||
- Do a PR
|
||||
- DM us to collect your bounty!
|
||||
113
common/scripts/SHA384withECDSA.ts
Normal file
113
common/scripts/SHA384withECDSA.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import assert from "assert";
|
||||
import { PassportData } from "../src/utils/types";
|
||||
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, arraysAreEqual, findSubarrayIndex } from "../src/utils/utils";
|
||||
import * as forge from 'node-forge';
|
||||
import { writeFileSync } from "fs";
|
||||
import elliptic from 'elliptic';
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
const sampleMRZ = "P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02"
|
||||
const sampleDataHashes = [
|
||||
[
|
||||
2,
|
||||
[-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128, -8, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38]
|
||||
],
|
||||
[
|
||||
3,
|
||||
[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]
|
||||
],
|
||||
[
|
||||
11,
|
||||
[-120, -101, 87, -112, 111, 15, -104, 127, 85, 25, -102, 81, 20, 58, 51, 75, -63, 116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124]
|
||||
],
|
||||
[
|
||||
12,
|
||||
[41, -22, 106, 78, 31, 11, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -42, 53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114]
|
||||
],
|
||||
[
|
||||
13,
|
||||
[91, -34, -46, -63, 62, -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, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38]
|
||||
]
|
||||
] as [number, number[]][]
|
||||
const signatureAlgorithm = 'SHA384withECDSA'
|
||||
const hashLen = 46
|
||||
|
||||
export function genMockPassportData_SHA384withECDSA(): PassportData {
|
||||
const mrzHash = hash(signatureAlgorithm, formatMrz(sampleMRZ));
|
||||
sampleDataHashes.unshift([1, mrzHash]);
|
||||
const concatenatedDataHashes = formatAndConcatenateDataHashes(
|
||||
[[1, mrzHash], ...sampleDataHashes],
|
||||
hashLen,
|
||||
33
|
||||
);
|
||||
const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));
|
||||
|
||||
const ec = new elliptic.ec('p384');
|
||||
const keyPair = ec.genKeyPair();
|
||||
const pubKey = keyPair.getPublic();
|
||||
|
||||
const md = forge.md.sha384.create();
|
||||
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
|
||||
const signature = keyPair.sign(md.digest().toHex(), 'hex');
|
||||
const signatureBytes = Array.from(Buffer.from(signature.toDER(), 'hex'));
|
||||
|
||||
const Qx = pubKey.getX().toString(16);
|
||||
const Qy = pubKey.getY().toString(16);
|
||||
|
||||
return {
|
||||
mrz: sampleMRZ,
|
||||
signatureAlgorithm: signatureAlgorithm,
|
||||
pubKey: {
|
||||
publicKeyQ: `(${Qx},${Qy},1,fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc)`
|
||||
},
|
||||
dataGroupHashes: concatenatedDataHashes,
|
||||
eContent: eContent,
|
||||
encryptedDigest: signatureBytes,
|
||||
photoBase64: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3..."
|
||||
}
|
||||
}
|
||||
|
||||
function verify(passportData: PassportData): boolean {
|
||||
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = passportData;
|
||||
const formattedMrz = formatMrz(mrz);
|
||||
const mrzHash = hash(signatureAlgorithm, formattedMrz);
|
||||
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash)
|
||||
console.log('dg1HashOffset', dg1HashOffset);
|
||||
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');
|
||||
|
||||
const concatHash = hash(signatureAlgorithm, dataGroupHashes)
|
||||
assert(
|
||||
arraysAreEqual(
|
||||
concatHash,
|
||||
eContent.slice(eContent.length - concatHash.length)
|
||||
),
|
||||
'concatHash is not at the right place in eContent'
|
||||
);
|
||||
|
||||
const cleanPublicKeyQ = pubKey.publicKeyQ.replace(/[()]/g, '').split(',');
|
||||
const Qx = cleanPublicKeyQ[0];
|
||||
const Qy = cleanPublicKeyQ[1];
|
||||
|
||||
const ec = new elliptic.ec('p384');
|
||||
const key = ec.keyFromPublic({ x: Qx, y: Qy }, 'hex');
|
||||
|
||||
const messageBuffer = Buffer.from(eContent);
|
||||
const msgHash = crypto.createHash('sha384').update(messageBuffer).digest();
|
||||
|
||||
const signature = Buffer.from(encryptedDigest).toString('hex');
|
||||
|
||||
const isValid = key.verify(msgHash, signature);
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
|
||||
const mockPassportData = genMockPassportData_SHA384withECDSA();
|
||||
console.log("Passport Data:", JSON.stringify(mockPassportData, null, 2));
|
||||
console.log("Signature valid:", verify(mockPassportData));
|
||||
|
||||
writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2));
|
||||
474
common/scripts/passportData.json
Normal file
474
common/scripts/passportData.json
Normal file
@@ -0,0 +1,474 @@
|
||||
{
|
||||
"mrz": "P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02",
|
||||
"signatureAlgorithm": "sha1WithRSAEncryption",
|
||||
"pubKey": {
|
||||
"modulus": "25825429057059192136108879878584777378654757240338449850333826035522788688006003098652086918620774520803490546755795078682140839966138109158244063837927200135790195224745239859057220329386561601721351696226057564841628462419818778146307352956712449575319326790354320318538693617555205343313027743984395735323775616464067940972666996572033472954611814220870194705592266623708066532169995623347732878333242475140240755230523341780618713394357686812647104201915704768910310961389728873036708721827192621939370755343467271300872482189554492692990185310969209988312747691889806959985764889980641836439721025225230179760027",
|
||||
"exponent": "65537"
|
||||
},
|
||||
"dataGroupHashes": [
|
||||
58,
|
||||
-127,
|
||||
-82,
|
||||
12,
|
||||
-127,
|
||||
-122,
|
||||
96,
|
||||
100,
|
||||
24,
|
||||
117,
|
||||
-114,
|
||||
37,
|
||||
-38,
|
||||
115,
|
||||
-43,
|
||||
29,
|
||||
31,
|
||||
-120,
|
||||
0,
|
||||
55,
|
||||
123,
|
||||
95,
|
||||
-5,
|
||||
-51,
|
||||
-36,
|
||||
-14,
|
||||
-55,
|
||||
-81,
|
||||
-64,
|
||||
1,
|
||||
50,
|
||||
-96,
|
||||
114,
|
||||
-93,
|
||||
25,
|
||||
75,
|
||||
70,
|
||||
94,
|
||||
85,
|
||||
95,
|
||||
40,
|
||||
-11,
|
||||
-101,
|
||||
88,
|
||||
-85,
|
||||
-108,
|
||||
-10,
|
||||
-44,
|
||||
104,
|
||||
-62,
|
||||
-117,
|
||||
-66,
|
||||
82,
|
||||
-76,
|
||||
-21,
|
||||
-34,
|
||||
33,
|
||||
79,
|
||||
50,
|
||||
-104,
|
||||
-120,
|
||||
-114,
|
||||
35,
|
||||
116,
|
||||
-32,
|
||||
6,
|
||||
-14,
|
||||
-100,
|
||||
-115,
|
||||
-128,
|
||||
-8,
|
||||
0,
|
||||
-62,
|
||||
104,
|
||||
108,
|
||||
-19,
|
||||
-10,
|
||||
97,
|
||||
-26,
|
||||
116,
|
||||
-58,
|
||||
69,
|
||||
110,
|
||||
26,
|
||||
87,
|
||||
17,
|
||||
89,
|
||||
110,
|
||||
-57,
|
||||
108,
|
||||
-6,
|
||||
76,
|
||||
123,
|
||||
-40,
|
||||
13,
|
||||
51,
|
||||
-29,
|
||||
72,
|
||||
-11,
|
||||
59,
|
||||
-63,
|
||||
-18,
|
||||
-90,
|
||||
103,
|
||||
49,
|
||||
23,
|
||||
-92,
|
||||
-85,
|
||||
-68,
|
||||
-62,
|
||||
-59
|
||||
],
|
||||
"eContent": [
|
||||
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,
|
||||
-44,
|
||||
-111,
|
||||
1,
|
||||
94,
|
||||
-94,
|
||||
0,
|
||||
-44,
|
||||
-10,
|
||||
92,
|
||||
45,
|
||||
51,
|
||||
-75,
|
||||
9,
|
||||
107,
|
||||
0,
|
||||
93,
|
||||
73,
|
||||
104,
|
||||
-127,
|
||||
-71
|
||||
],
|
||||
"encryptedDigest": [
|
||||
22,
|
||||
247,
|
||||
66,
|
||||
163,
|
||||
144,
|
||||
4,
|
||||
210,
|
||||
177,
|
||||
130,
|
||||
237,
|
||||
4,
|
||||
44,
|
||||
87,
|
||||
28,
|
||||
70,
|
||||
24,
|
||||
248,
|
||||
5,
|
||||
240,
|
||||
162,
|
||||
234,
|
||||
93,
|
||||
62,
|
||||
124,
|
||||
109,
|
||||
165,
|
||||
227,
|
||||
92,
|
||||
71,
|
||||
199,
|
||||
101,
|
||||
98,
|
||||
15,
|
||||
132,
|
||||
23,
|
||||
191,
|
||||
36,
|
||||
158,
|
||||
211,
|
||||
56,
|
||||
127,
|
||||
72,
|
||||
134,
|
||||
133,
|
||||
217,
|
||||
210,
|
||||
217,
|
||||
34,
|
||||
3,
|
||||
77,
|
||||
16,
|
||||
139,
|
||||
55,
|
||||
25,
|
||||
8,
|
||||
83,
|
||||
161,
|
||||
2,
|
||||
179,
|
||||
201,
|
||||
57,
|
||||
19,
|
||||
233,
|
||||
67,
|
||||
225,
|
||||
54,
|
||||
195,
|
||||
226,
|
||||
16,
|
||||
22,
|
||||
130,
|
||||
96,
|
||||
18,
|
||||
206,
|
||||
170,
|
||||
208,
|
||||
171,
|
||||
126,
|
||||
180,
|
||||
137,
|
||||
62,
|
||||
195,
|
||||
226,
|
||||
206,
|
||||
111,
|
||||
82,
|
||||
171,
|
||||
199,
|
||||
128,
|
||||
147,
|
||||
156,
|
||||
156,
|
||||
32,
|
||||
5,
|
||||
175,
|
||||
187,
|
||||
135,
|
||||
227,
|
||||
51,
|
||||
0,
|
||||
228,
|
||||
175,
|
||||
251,
|
||||
2,
|
||||
231,
|
||||
85,
|
||||
168,
|
||||
160,
|
||||
9,
|
||||
133,
|
||||
158,
|
||||
175,
|
||||
135,
|
||||
42,
|
||||
59,
|
||||
13,
|
||||
113,
|
||||
211,
|
||||
132,
|
||||
92,
|
||||
140,
|
||||
106,
|
||||
36,
|
||||
191,
|
||||
109,
|
||||
213,
|
||||
214,
|
||||
57,
|
||||
76,
|
||||
35,
|
||||
132,
|
||||
176,
|
||||
116,
|
||||
130,
|
||||
212,
|
||||
101,
|
||||
115,
|
||||
28,
|
||||
116,
|
||||
203,
|
||||
9,
|
||||
98,
|
||||
10,
|
||||
68,
|
||||
219,
|
||||
128,
|
||||
68,
|
||||
110,
|
||||
177,
|
||||
175,
|
||||
210,
|
||||
80,
|
||||
144,
|
||||
65,
|
||||
236,
|
||||
128,
|
||||
249,
|
||||
219,
|
||||
189,
|
||||
216,
|
||||
36,
|
||||
234,
|
||||
61,
|
||||
75,
|
||||
53,
|
||||
101,
|
||||
224,
|
||||
126,
|
||||
82,
|
||||
207,
|
||||
65,
|
||||
182,
|
||||
254,
|
||||
133,
|
||||
251,
|
||||
103,
|
||||
219,
|
||||
207,
|
||||
17,
|
||||
172,
|
||||
26,
|
||||
139,
|
||||
120,
|
||||
184,
|
||||
183,
|
||||
176,
|
||||
192,
|
||||
102,
|
||||
19,
|
||||
184,
|
||||
252,
|
||||
146,
|
||||
175,
|
||||
169,
|
||||
252,
|
||||
3,
|
||||
170,
|
||||
141,
|
||||
13,
|
||||
136,
|
||||
248,
|
||||
94,
|
||||
237,
|
||||
158,
|
||||
114,
|
||||
149,
|
||||
155,
|
||||
241,
|
||||
169,
|
||||
161,
|
||||
99,
|
||||
239,
|
||||
55,
|
||||
30,
|
||||
125,
|
||||
219,
|
||||
65,
|
||||
43,
|
||||
64,
|
||||
12,
|
||||
243,
|
||||
138,
|
||||
114,
|
||||
150,
|
||||
32,
|
||||
165,
|
||||
220,
|
||||
91,
|
||||
199,
|
||||
176,
|
||||
30,
|
||||
156,
|
||||
10,
|
||||
199,
|
||||
196,
|
||||
152,
|
||||
4,
|
||||
194,
|
||||
145,
|
||||
163,
|
||||
66,
|
||||
212,
|
||||
239,
|
||||
164,
|
||||
248,
|
||||
242,
|
||||
26,
|
||||
51,
|
||||
235,
|
||||
101,
|
||||
95,
|
||||
133,
|
||||
142,
|
||||
189,
|
||||
226,
|
||||
195
|
||||
],
|
||||
"photoBase64": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3..."
|
||||
}
|
||||
128
common/scripts/rsassaPss_65537.ts
Normal file
128
common/scripts/rsassaPss_65537.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import assert from "assert";
|
||||
import { PassportData } from "../src/utils/types";
|
||||
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, arraysAreEqual, findSubarrayIndex } from "../src/utils/utils";
|
||||
import * as forge from 'node-forge';
|
||||
import crypto from 'crypto';
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
const dsc_key = readFileSync('../common/src/mock_certificates/sha256_rsa_4096/mock_dsc.key', 'utf8');
|
||||
const dsc_crt = readFileSync('../common/src/mock_certificates/sha256_rsa_4096/mock_dsc.crt', 'utf8');
|
||||
const sampleMRZ = "P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02"
|
||||
const sampleDataHashes = [
|
||||
[
|
||||
2,
|
||||
[-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128, -8, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38]
|
||||
],
|
||||
[
|
||||
3,
|
||||
[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]
|
||||
],
|
||||
[
|
||||
11,
|
||||
[-120, -101, 87, -112, 111, 15, -104, 127, 85, 25, -102, 81, 20, 58, 51, 75, -63, 116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124]
|
||||
],
|
||||
[
|
||||
12,
|
||||
[41, -22, 106, 78, 31, 11, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -42, 53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114]
|
||||
],
|
||||
[
|
||||
13,
|
||||
[91, -34, -46, -63, 62, -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, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38]
|
||||
]
|
||||
] as [number, number[]][]
|
||||
const signatureAlgorithm = 'sha256WithRSASSAPSS'
|
||||
const hashLen = 32
|
||||
|
||||
export function genMockPassportData_sha256WithRSASSAPSS_65537(): PassportData {
|
||||
const privateKeyPem = forge.pki.privateKeyFromPem(dsc_key);
|
||||
const privateKeyPemString = forge.pki.privateKeyToPem(privateKeyPem);
|
||||
const certificate = forge.pki.certificateFromPem(dsc_crt);
|
||||
|
||||
const publicKey = certificate.publicKey as forge.pki.rsa.PublicKey;
|
||||
|
||||
const modulus = (publicKey as any).n.toString(10);
|
||||
const exponent = (publicKey as any).e.toString(10);
|
||||
const salt = Buffer.from('dee959c7e06411361420ff80185ed57f3e6776afdee959c7e064113614201420', 'hex');
|
||||
|
||||
const mrzHash = hash(signatureAlgorithm, formatMrz(sampleMRZ));
|
||||
const concatenatedDataHashes = formatAndConcatenateDataHashes(
|
||||
[[1, mrzHash], ...sampleDataHashes],
|
||||
hashLen,
|
||||
30
|
||||
);
|
||||
|
||||
const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));
|
||||
|
||||
|
||||
const my_message = Buffer.from(eContent);
|
||||
const hash_algorithm = 'sha256';
|
||||
|
||||
const private_key = {
|
||||
key: privateKeyPem,
|
||||
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
||||
saltLength: salt.length,
|
||||
};
|
||||
|
||||
const signature = crypto.sign(hash_algorithm, my_message, privateKeyPemString);
|
||||
const signatureArray = Array.from(signature, byte => byte < 128 ? byte : byte - 256);
|
||||
|
||||
return {
|
||||
mrz: sampleMRZ,
|
||||
signatureAlgorithm: signatureAlgorithm,
|
||||
pubKey: {
|
||||
modulus: modulus,
|
||||
exponent: exponent,
|
||||
},
|
||||
dataGroupHashes: concatenatedDataHashes,
|
||||
eContent: eContent,
|
||||
encryptedDigest: signatureArray,
|
||||
photoBase64: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3..."
|
||||
}
|
||||
}
|
||||
|
||||
function verify(passportData: PassportData): boolean {
|
||||
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = passportData;
|
||||
const formattedMrz = formatMrz(mrz);
|
||||
const mrzHash = hash(signatureAlgorithm, formattedMrz);
|
||||
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash)
|
||||
console.log('dg1HashOffset', dg1HashOffset);
|
||||
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');
|
||||
|
||||
const concatHash = hash(signatureAlgorithm, dataGroupHashes)
|
||||
assert(
|
||||
arraysAreEqual(
|
||||
concatHash,
|
||||
eContent.slice(eContent.length - concatHash.length)
|
||||
),
|
||||
'concatHash is not at the right place in eContent'
|
||||
);
|
||||
|
||||
const modulus = new forge.jsbn.BigInteger(pubKey.modulus, 10);
|
||||
const exponent = new forge.jsbn.BigInteger(pubKey.exponent, 10);
|
||||
const publicKey = forge.pki.setRsaPublicKey(modulus, exponent);
|
||||
const pem = forge.pki.publicKeyToPem(publicKey);
|
||||
const rsa_public = Buffer.from(pem);
|
||||
|
||||
const message = Buffer.from(eContent);
|
||||
const signature = Buffer.from(encryptedDigest);
|
||||
const hash_algorithm = "sha256";
|
||||
|
||||
const public_key = {
|
||||
key: rsa_public,
|
||||
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
||||
saltLength: 32,
|
||||
};
|
||||
|
||||
const isVerified = crypto.verify(hash_algorithm, message, public_key, signature);
|
||||
|
||||
return isVerified;
|
||||
}
|
||||
|
||||
const mockPassportData = genMockPassportData_sha256WithRSASSAPSS_65537();
|
||||
console.log("Passport Data:", JSON.stringify(mockPassportData, null, 2));
|
||||
console.log("Signature valid:", verify(mockPassportData));
|
||||
|
||||
writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2));
|
||||
221
common/scripts/rsassaPss_65537_full_form.ts
Normal file
221
common/scripts/rsassaPss_65537_full_form.ts
Normal file
@@ -0,0 +1,221 @@
|
||||
// this file shows the fully explicit form of RSASSA-PSS, based on https://github.com/shigeki/ohtsu_rsa_pss_js/.
|
||||
// It can be useful to implement the circuit
|
||||
// It is currently broken so the line that errors is commented
|
||||
|
||||
import assert from "assert";
|
||||
import { PassportData } from "../src/utils/types";
|
||||
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, arraysAreEqual, findSubarrayIndex } from "../src/utils/utils";
|
||||
import * as forge from 'node-forge';
|
||||
import crypto from 'crypto';
|
||||
import { writeFileSync } from "fs";
|
||||
|
||||
const sampleMRZ = "P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02"
|
||||
const sampleDataHashes = [
|
||||
[
|
||||
2,
|
||||
[-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128, -8, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38]
|
||||
],
|
||||
[
|
||||
3,
|
||||
[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]
|
||||
],
|
||||
[
|
||||
11,
|
||||
[-120, -101, 87, -112, 111, 15, -104, 127, 85, 25, -102, 81, 20, 58, 51, 75, -63, 116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124]
|
||||
],
|
||||
[
|
||||
12,
|
||||
[41, -22, 106, 78, 31, 11, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -42, 53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114]
|
||||
],
|
||||
[
|
||||
13,
|
||||
[91, -34, -46, -63, 62, -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, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38]
|
||||
]
|
||||
] as [number, number[]][]
|
||||
const signatureAlgorithm = 'sha256WithRSASSAPSS'
|
||||
const hashLen = 32
|
||||
|
||||
export function genMockPassportData_sha256WithRSASSAPSS_65537(): PassportData {
|
||||
const keypair = forge.pki.rsa.generateKeyPair(2048);
|
||||
const privateKeyPem = forge.pki.privateKeyToPem(keypair.privateKey);
|
||||
|
||||
const publicKey = keypair.publicKey;
|
||||
const modulus = publicKey.n.toString(10);
|
||||
const exponent = publicKey.e.toString(10);
|
||||
const salt = Buffer.from('dee959c7e06411361420ff80185ed57f3e6776afdee959c7e064113614201420', 'hex');
|
||||
|
||||
const mrzHash = hash(signatureAlgorithm, formatMrz(sampleMRZ));
|
||||
const concatenatedDataHashes = formatAndConcatenateDataHashes(
|
||||
[[1, mrzHash], ...sampleDataHashes],
|
||||
hashLen,
|
||||
30
|
||||
);
|
||||
|
||||
const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));
|
||||
|
||||
const my_message = Buffer.from(eContent);
|
||||
const sLen = 32;
|
||||
const keylen = 2048;
|
||||
const hash_algorithm = 'sha256';
|
||||
const emBits = keylen - 1;
|
||||
const emLen = Math.ceil(emBits / 8);
|
||||
const hLen = 32;
|
||||
|
||||
console.log('my_message:', my_message);
|
||||
|
||||
const private_key = {
|
||||
key: Buffer.from(privateKeyPem),
|
||||
padding: crypto.constants.RSA_NO_PADDING
|
||||
};
|
||||
|
||||
const padding1 = Buffer.alloc(8);
|
||||
const hash1 = crypto.createHash(hash_algorithm);
|
||||
hash1.update(my_message);
|
||||
const mHash = hash1.digest();
|
||||
|
||||
if (emLen < hLen + sLen + 2) {
|
||||
throw new Error('encoding error');
|
||||
}
|
||||
|
||||
var padding2 = Buffer.alloc(emLen - sLen - hLen - 2);
|
||||
const DB = Buffer.concat([padding2, Buffer.from('01', 'hex'), salt]);
|
||||
|
||||
const hash2 = crypto.createHash(hash_algorithm);
|
||||
hash2.update(Buffer.concat([padding1, mHash, salt]));
|
||||
|
||||
const H = hash2.digest();
|
||||
const dbMask = MGF1(H, emLen - hLen - 1, hLen, hash_algorithm);
|
||||
var maskedDB = BufferXOR(DB, dbMask);
|
||||
var b = Buffer.concat([maskedDB, H, Buffer.from('bc', 'hex')]);
|
||||
var signature = crypto.privateEncrypt(private_key, b);
|
||||
const signatureArray = Array.from(signature, byte => byte < 128 ? byte : byte - 256);
|
||||
|
||||
// const signatureBytes = Array.from(signature, (c: string) => c.charCodeAt(0));
|
||||
|
||||
return {
|
||||
mrz: sampleMRZ,
|
||||
signatureAlgorithm: signatureAlgorithm,
|
||||
pubKey: {
|
||||
modulus: modulus,
|
||||
exponent: exponent,
|
||||
},
|
||||
dataGroupHashes: concatenatedDataHashes,
|
||||
eContent: eContent,
|
||||
encryptedDigest: signatureArray,
|
||||
photoBase64: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3..."
|
||||
}
|
||||
}
|
||||
|
||||
function verify(passportData: PassportData): boolean {
|
||||
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = passportData;
|
||||
const formattedMrz = formatMrz(mrz);
|
||||
const mrzHash = hash(signatureAlgorithm, formattedMrz);
|
||||
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash)
|
||||
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');
|
||||
|
||||
const concatHash = hash(signatureAlgorithm, dataGroupHashes)
|
||||
assert(
|
||||
arraysAreEqual(
|
||||
concatHash,
|
||||
eContent.slice(eContent.length - concatHash.length)
|
||||
),
|
||||
'concatHash is not at the right place in eContent'
|
||||
);
|
||||
|
||||
const modulus = new forge.jsbn.BigInteger(pubKey.modulus, 10);
|
||||
const exponent = new forge.jsbn.BigInteger(pubKey.exponent, 10);
|
||||
const publicKey = forge.pki.setRsaPublicKey(modulus, exponent);
|
||||
const pem = forge.pki.publicKeyToPem(publicKey);
|
||||
const rsa_public = Buffer.from(pem);
|
||||
|
||||
const message = Buffer.from(eContent);
|
||||
const sLen = 32;
|
||||
const keylen = 2048;
|
||||
const signature = Buffer.from(encryptedDigest);
|
||||
const hash_algorithm = "sha256";
|
||||
const hLen = 32;
|
||||
|
||||
assert(Buffer.isBuffer(rsa_public));
|
||||
assert.strictEqual(typeof keylen, "number");
|
||||
assert.strictEqual(typeof hash_algorithm, "string");
|
||||
assert(Buffer.isBuffer(message));
|
||||
assert.strictEqual(typeof sLen, "number");
|
||||
assert(Buffer.isBuffer(signature));
|
||||
|
||||
const public_key = {
|
||||
key: rsa_public,
|
||||
padding: crypto.constants.RSA_NO_PADDING,
|
||||
};
|
||||
|
||||
var m = crypto.publicDecrypt(public_key, signature);
|
||||
|
||||
const emBits = keylen - 1;
|
||||
assert(hLen);
|
||||
const emLen = Math.ceil(emBits / 8);
|
||||
|
||||
const hash1 = crypto.createHash(hash_algorithm);
|
||||
hash1.update(message);
|
||||
const mHash = hash1.digest();
|
||||
|
||||
console.log("emLen", emLen);
|
||||
console.log("hLen", hLen);
|
||||
console.log("sLen", sLen);
|
||||
if (emLen < hLen + sLen + 2) throw new Error("inconsistent");
|
||||
|
||||
if (m[m.length - 1] !== 0xbc) throw new Error("inconsistent");
|
||||
|
||||
const maskedDB = m.slice(0, emLen - hLen - 1);
|
||||
const H = m.slice(emLen - hLen - 1, emLen - 1);
|
||||
|
||||
// if ((maskedDB[0] & 0x80) !== 0x00) throw new Error("inconsistent");
|
||||
|
||||
const dbMask = MGF1(H, emLen - hLen - 1, hLen, hash_algorithm);
|
||||
const DB = BufferXOR(maskedDB, dbMask);
|
||||
DB[0] = DB[0] & 0x7f;
|
||||
for (var i = 0; i < emLen - hLen - sLen - 2; i++) {
|
||||
assert.strictEqual(DB[i], 0x00);
|
||||
}
|
||||
assert.strictEqual(DB[emLen - hLen - sLen - 2], 0x01);
|
||||
const salt = DB.slice(-sLen);
|
||||
const MDash = Buffer.concat([Buffer.alloc(8), mHash, salt]);
|
||||
const hash2 = crypto.createHash(hash_algorithm);
|
||||
hash2.update(MDash);
|
||||
const HDash = hash2.digest();
|
||||
return HDash.equals(H);
|
||||
}
|
||||
|
||||
function MGF1(mgfSeed: Buffer, maskLen: number, hLen: number, hash_algorithm: string) {
|
||||
if (maskLen > 0xffffffff * hLen) {
|
||||
throw new Error("mask too long");
|
||||
}
|
||||
var T = [];
|
||||
for (var i = 0; i <= Math.ceil(maskLen / hLen) - 1; i++) {
|
||||
var C = Buffer.alloc(4);
|
||||
C.writeUInt32BE(i);
|
||||
const hash3 = crypto.createHash(hash_algorithm);
|
||||
hash3.update(Buffer.concat([mgfSeed, C]));
|
||||
T.push(hash3.digest());
|
||||
}
|
||||
return Buffer.concat(T).slice(0, maskLen);
|
||||
}
|
||||
|
||||
function BufferXOR(a: Buffer, b: Buffer) {
|
||||
assert(a.length === b.length, "Buffers must have the same length");
|
||||
var c = Buffer.alloc(a.length);
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
c[i] = a[i] ^ b[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const mockPassportData = genMockPassportData_sha256WithRSASSAPSS_65537();
|
||||
console.log("Passport Data:", JSON.stringify(mockPassportData, null, 2));
|
||||
console.log("Signature valid:", verify(mockPassportData));
|
||||
|
||||
writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2));
|
||||
|
||||
94
common/scripts/sha1WithRSAEncryption_65537.ts
Normal file
94
common/scripts/sha1WithRSAEncryption_65537.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
import { PassportData } from "../src/utils/types";
|
||||
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, hexToDecimal, arraysAreEqual, findSubarrayIndex } from "../src/utils/utils";
|
||||
import * as forge from 'node-forge';
|
||||
import { assert } from "console";
|
||||
const dsc_key = readFileSync('../common/src/mock_certificates/sha1_rsa_2048/mock_dsc.key', 'utf8');
|
||||
|
||||
const sampleMRZ = "P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02"
|
||||
const sampleDataHashes = [
|
||||
[
|
||||
2,
|
||||
[-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128, -8]
|
||||
],
|
||||
[
|
||||
3,
|
||||
[0, -62, 104, 108, -19, -10, 97, -26, 116, -58, 69, 110, 26, 87, 17, 89, 110, -57, 108, -6]
|
||||
],
|
||||
[
|
||||
14,
|
||||
[76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59]
|
||||
]
|
||||
] as [number, number[]][]
|
||||
const signatureAlgorithm = 'sha1WithRSAEncryption'
|
||||
const hashLen = 20
|
||||
|
||||
export function genMockPassportData_sha1WithRSAEncryption_65537(): PassportData {
|
||||
const mrzHash = hash(signatureAlgorithm, formatMrz(sampleMRZ));
|
||||
const concatenatedDataHashes = formatAndConcatenateDataHashes(
|
||||
[[1, mrzHash], ...sampleDataHashes],
|
||||
hashLen,
|
||||
31 // could have been different
|
||||
);
|
||||
|
||||
const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));
|
||||
|
||||
const privKey = forge.pki.privateKeyFromPem(dsc_key);
|
||||
const modulus = privKey.n.toString(16);
|
||||
|
||||
const md = forge.md.sha1.create();
|
||||
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
|
||||
|
||||
const signature = privKey.sign(md)
|
||||
const signatureBytes = Array.from(signature, (c: string) => c.charCodeAt(0));
|
||||
|
||||
return {
|
||||
mrz: sampleMRZ,
|
||||
signatureAlgorithm: signatureAlgorithm,
|
||||
pubKey: {
|
||||
modulus: hexToDecimal(modulus),
|
||||
exponent: '65537',
|
||||
},
|
||||
dataGroupHashes: concatenatedDataHashes,
|
||||
eContent: eContent,
|
||||
encryptedDigest: signatureBytes,
|
||||
photoBase64: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3..."
|
||||
}
|
||||
}
|
||||
|
||||
function verify(passportData: PassportData): boolean {
|
||||
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = passportData;
|
||||
const formattedMrz = formatMrz(mrz);
|
||||
const mrzHash = hash(signatureAlgorithm, formattedMrz);
|
||||
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash)
|
||||
console.log('dg1HashOffset', dg1HashOffset);
|
||||
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');
|
||||
|
||||
const concatHash = hash(signatureAlgorithm, dataGroupHashes)
|
||||
assert(
|
||||
arraysAreEqual(
|
||||
concatHash,
|
||||
eContent.slice(eContent.length - concatHash.length)
|
||||
),
|
||||
'concatHash is not at the right place in eContent'
|
||||
);
|
||||
|
||||
const modulus = new forge.jsbn.BigInteger(pubKey.modulus, 10);
|
||||
const exponent = new forge.jsbn.BigInteger(pubKey.exponent, 10);
|
||||
const rsaPublicKey = forge.pki.rsa.setPublicKey(modulus, exponent);
|
||||
|
||||
const md = forge.md.sha1.create();
|
||||
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
|
||||
|
||||
const signature = Buffer.from(encryptedDigest).toString(
|
||||
'binary',
|
||||
);
|
||||
|
||||
return rsaPublicKey.verify(md.digest().bytes(), signature);
|
||||
}
|
||||
|
||||
const mockPassportData = genMockPassportData_sha1WithRSAEncryption_65537();
|
||||
console.log("Passport Data:", JSON.stringify(mockPassportData, null, 2));
|
||||
console.log("Signature valid:", verify(mockPassportData));
|
||||
|
||||
writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2));
|
||||
109
common/scripts/sha256WithRSAEncryption_65537.ts
Normal file
109
common/scripts/sha256WithRSAEncryption_65537.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import assert from "assert";
|
||||
import { PassportData } from "../src/utils/types";
|
||||
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, hexToDecimal, arraysAreEqual, findSubarrayIndex } from "../src/utils/utils";
|
||||
import * as forge from 'node-forge';
|
||||
import { writeFileSync, readFileSync } from "fs";
|
||||
|
||||
const dsc_key = readFileSync('../common/src/mock_certificates/sha256_rsa_4096/mock_dsc.key', 'utf8');
|
||||
|
||||
const sampleMRZ = "P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02"
|
||||
const sampleDataHashes = [
|
||||
[
|
||||
2,
|
||||
[-66, 82, -76, -21, -34, 33, 79, 50, -104, -120, -114, 35, 116, -32, 6, -14, -100, -115, -128, -8, 10, 61, 98, 86, -8, 45, -49, -46, 90, -24, -81, 38]
|
||||
],
|
||||
[
|
||||
3,
|
||||
[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]
|
||||
],
|
||||
[
|
||||
11,
|
||||
[-120, -101, 87, -112, 111, 15, -104, 127, 85, 25, -102, 81, 20, 58, 51, 75, -63, 116, -22, 0, 60, 30, 29, 30, -73, -115, 72, -9, -1, -53, 100, 124]
|
||||
],
|
||||
[
|
||||
12,
|
||||
[41, -22, 106, 78, 31, 11, 114, -119, -19, 17, 92, 71, -122, 47, 62, 78, -67, -23, -55, -42, 53, 4, 47, -67, -55, -123, 6, 121, 34, -125, 64, -114]
|
||||
],
|
||||
[
|
||||
13,
|
||||
[91, -34, -46, -63, 62, -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, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38]
|
||||
]
|
||||
] as [number, number[]][]
|
||||
const signatureAlgorithm = 'sha256WithRSAEncryption'
|
||||
const hashLen = 32
|
||||
|
||||
export function genMockPassportData_sha256WithRSAEncryption_65537(): PassportData {
|
||||
const mrzHash = hash(signatureAlgorithm, formatMrz(sampleMRZ));
|
||||
const concatenatedDataHashes = formatAndConcatenateDataHashes(
|
||||
[[1, mrzHash], ...sampleDataHashes],
|
||||
hashLen,
|
||||
31
|
||||
);
|
||||
|
||||
const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));
|
||||
|
||||
//const rsa = forge.pki.rsa;
|
||||
//const privKey = rsa.generateKeyPair({ bits: 2048 }).privateKey;
|
||||
const privKey = forge.pki.privateKeyFromPem(dsc_key);
|
||||
const modulus = privKey.n.toString(16);
|
||||
|
||||
const md = forge.md.sha256.create();
|
||||
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
|
||||
|
||||
const signature = privKey.sign(md)
|
||||
const signatureBytes = Array.from(signature, (c: string) => c.charCodeAt(0));
|
||||
|
||||
return {
|
||||
mrz: sampleMRZ,
|
||||
signatureAlgorithm: signatureAlgorithm,
|
||||
pubKey: {
|
||||
modulus: hexToDecimal(modulus),
|
||||
exponent: '65537',
|
||||
},
|
||||
dataGroupHashes: concatenatedDataHashes,
|
||||
eContent: eContent,
|
||||
encryptedDigest: signatureBytes,
|
||||
photoBase64: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3..."
|
||||
}
|
||||
}
|
||||
|
||||
function verify(passportData: PassportData): boolean {
|
||||
const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = passportData;
|
||||
const formattedMrz = formatMrz(mrz);
|
||||
const mrzHash = hash(signatureAlgorithm, formattedMrz);
|
||||
const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash)
|
||||
console.log('dg1HashOffset', dg1HashOffset);
|
||||
assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes');
|
||||
|
||||
const concatHash = hash(signatureAlgorithm, dataGroupHashes)
|
||||
assert(
|
||||
arraysAreEqual(
|
||||
concatHash,
|
||||
eContent.slice(eContent.length - hashLen)
|
||||
),
|
||||
'concatHash is not at the right place in eContent'
|
||||
);
|
||||
|
||||
const modulus = new forge.jsbn.BigInteger(pubKey.modulus, 10);
|
||||
const exponent = new forge.jsbn.BigInteger(pubKey.exponent, 10);
|
||||
const rsaPublicKey = forge.pki.rsa.setPublicKey(modulus, exponent);
|
||||
|
||||
const md = forge.md.sha256.create();
|
||||
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
|
||||
|
||||
const signature = Buffer.from(encryptedDigest).toString(
|
||||
'binary',
|
||||
);
|
||||
|
||||
return rsaPublicKey.verify(md.digest().bytes(), signature);
|
||||
}
|
||||
|
||||
const mockPassportData = genMockPassportData_sha256WithRSAEncryption_65537();
|
||||
console.log("Passport Data:", JSON.stringify(mockPassportData, null, 2));
|
||||
console.log("Signature valid:", verify(mockPassportData));
|
||||
|
||||
writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2));
|
||||
@@ -1,19 +1,18 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDCTCCAfGgAwIBAgIUVgXmIg3ZjJoGkQE2mwtKlcPI3bIwDQYJKoZIhvcNAQEF
|
||||
BQAwFDESMBAGA1UEAwwJbW9ja19jc2NhMB4XDTI0MDYyODEzNDUzMFoXDTI1MDYy
|
||||
ODEzNDUzMFowFDESMBAGA1UEAwwJbW9ja19jc2NhMIIBIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAQ8AMIIBCgKCAQEAmTkg9LzPdTsFgOL6uXHCGMylvo43XD5BpdION5nBFfx+
|
||||
tKxC30AH41JAbJBb8kDY1FXQPfmE63ROfU0W9oMh8vu/n+yCJ22F4xqgOA012cXw
|
||||
mEwa6A8dxeOqxv92dBdtN5XpcEne5FI1qzCCCRooQ5lMGikiGJiPVfXbIFPgVEv0
|
||||
uW/bbmbNwmm3FZbWFKtotWIbfvLi14/9isk9Bgb1yYaiRhhr1AIyz6Whpsgxc+WE
|
||||
GF8aOdmMzZWXouIyeaSr41R/PuXvOmkizg/YoJij4CDch42ofT/gtShP5k3uFa+G
|
||||
NnmObx492pE7oEmtbJYi3ixuzx4tmnej+On40QBoSQIDAQABo1MwUTAdBgNVHQ4E
|
||||
FgQUdTWxPLHwrq0uuqFF8jzGc1QPLOgwHwYDVR0jBBgwFoAUdTWxPLHwrq0uuqFF
|
||||
8jzGc1QPLOgwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAlxot
|
||||
U0kau1ukBqaaY8CrnxDYyW2WvxNLRSsT9M3I8V/XrDaok44qVl4yXg9p8dd7Pn8j
|
||||
2ddnYk+tRBTm1I3sjdq/nVJ4soEqGdoxCQIKhKio8cJ26AOjuDv2j9mCZS6a4ptF
|
||||
ZDpjuFA3Tuwaoxo5oygdk/0y1LX2ZLONn3moS/A/4mHwGID9jVBnwLsvYJNjHqBP
|
||||
Dw7AiAaGUWC4IzBYE05PEz1VhcfFx9Gk0GhGqjB31da4J4QFq7uTz/WTuqQM7yoh
|
||||
gy3qwxe+RisZnvsWHjrhmSyhVZJdUhqjvSnWF3LgJKux49VfRICsGbbWy8HXZzu0
|
||||
ogX7sybD35QELYoB7A==
|
||||
MIIC1zCCAb+gAwIBAgIUZipRXztCv63+iMkCt+ivpxwkAOAwDQYJKoZIhvcNAQEF
|
||||
BQAwFDESMBAGA1UEAwwJTW9jayBDU0NBMB4XDTI0MDcxMjE3NDIxNVoXDTM0MDcx
|
||||
MDE3NDIxNVowFDESMBAGA1UEAwwJTW9jayBDU0NBMIIBIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAQ8AMIIBCgKCAQEAvFuQiNhHOcXS8LMz8Tp76BIo6+ZZtythhcDaEVsroBWG
|
||||
K63OqD89PTgg4d90To6TcMGXZXJZe+JifWsB5Fo+sUfwdOoWQ3hNKfWadKrkZs4x
|
||||
dh/V05hJ4VAuaj9e2m937GQEsK9obG9MQnYZSlcODCYtIynM/IVmNr27I+s5fspP
|
||||
0mZM+8X3mgjpQSwUob5zMkl8ZzskJau2oY6ImhI6fLNxAisS3wu/akpEVtKI3K8i
|
||||
we99oPDO6xuHeuOQh0L6DbBdpYpF7jPOkah8zBQNfuENaCcjTxI2twrSN0YLuIsQ
|
||||
fiEKbUq8DO5aRng9sws1DTNlf9AyvSPYfkizNtNHWwIDAQABoyEwHzAdBgNVHQ4E
|
||||
FgQU16zJPs8xurwLQAoHiDOuUr+OmnQwDQYJKoZIhvcNAQEFBQADggEBAA6sMfoQ
|
||||
1y42gg4/XNh6SOxHhT2z3u0lHq5+BxVORx5QcIi3rh1sgTocRBkl+4tzXFxDOzGt
|
||||
RpVEOnM4VqbxgvuTLYPbZ3jnoS9S62w2if7xaOWexLO+3hsOtMIUrBfrfBax03/S
|
||||
Tg9gkA98zvV1jbokPL23UXRWufv7L44HIFr3bLeikdOmpf6Lvp1ORiUXjbMi9o+c
|
||||
ty+gWrxsV+825W3LGD/71DFSD4yS8wK9M9KLZb/21bt6tq4D/E3njnYbXID+1dTL
|
||||
WC/4nCtzhd5n6cq1wKl6VnZ6bcyYb8MSQ6Kd6vbew1UnRae8KmFsjr2tJ50ESTj4
|
||||
jQwzIZELkOP+EAE=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
15
common/src/mock_certificates/sha1_rsa_2048/mock_csca.csr
Normal file
15
common/src/mock_certificates/sha1_rsa_2048/mock_csca.csr
Normal file
@@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICWTCCAUECAQAwFDESMBAGA1UEAwwJTW9jayBDU0NBMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAvFuQiNhHOcXS8LMz8Tp76BIo6+ZZtythhcDaEVsr
|
||||
oBWGK63OqD89PTgg4d90To6TcMGXZXJZe+JifWsB5Fo+sUfwdOoWQ3hNKfWadKrk
|
||||
Zs4xdh/V05hJ4VAuaj9e2m937GQEsK9obG9MQnYZSlcODCYtIynM/IVmNr27I+s5
|
||||
fspP0mZM+8X3mgjpQSwUob5zMkl8ZzskJau2oY6ImhI6fLNxAisS3wu/akpEVtKI
|
||||
3K8iwe99oPDO6xuHeuOQh0L6DbBdpYpF7jPOkah8zBQNfuENaCcjTxI2twrSN0YL
|
||||
uIsQfiEKbUq8DO5aRng9sws1DTNlf9AyvSPYfkizNtNHWwIDAQABoAAwDQYJKoZI
|
||||
hvcNAQELBQADggEBAK09cR+mHmiK10DSkVlnrZIk6sXO2jksPBBh2LGwE4CQSaBz
|
||||
5C/XSQbXImkLWzkt2Kh2xYBCgjdoL8JNfsPYHWkjbN7OzOao0LM42a2o3mJZKixR
|
||||
jcsWQLerrgXqhzP61gm+UVcZ77o5bfMtt1/52bIkJaBWd8Ka59wnTM75JQMVzM0y
|
||||
R+dM7pSdvICzXvMc8NKZGOOROmAN3O317i5oFI89KgFQ0mhjjwdK7X8v9I7dhnHe
|
||||
lI7ESWn/WCnIiq1tlDW3VyKzKul9nBFV2lDM1pHdfez0c9rAzry3Lz0NkM+yAtta
|
||||
W4mf0Ybiz72mwkuY95Sk0+2GohR2BgYK3OjmVkw=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -1,28 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCZOSD0vM91OwWA
|
||||
4vq5ccIYzKW+jjdcPkGl0g43mcEV/H60rELfQAfjUkBskFvyQNjUVdA9+YTrdE59
|
||||
TRb2gyHy+7+f7IInbYXjGqA4DTXZxfCYTBroDx3F46rG/3Z0F203lelwSd7kUjWr
|
||||
MIIJGihDmUwaKSIYmI9V9dsgU+BUS/S5b9tuZs3CabcVltYUq2i1Yht+8uLXj/2K
|
||||
yT0GBvXJhqJGGGvUAjLPpaGmyDFz5YQYXxo52YzNlZei4jJ5pKvjVH8+5e86aSLO
|
||||
D9igmKPgINyHjah9P+C1KE/mTe4Vr4Y2eY5vHj3akTugSa1sliLeLG7PHi2ad6P4
|
||||
6fjRAGhJAgMBAAECggEAA8T8pzIKb12Xz5wLPkWazcdMwronCUH0VZRMJSjHOpIz
|
||||
GqDcG80sgdaKZHQC47wIluUIue+XVNS64MOv32RqO5sJ07EVjMtZsP9nkT1yStS0
|
||||
bAYU9DV5U77GOv36VRXln1Q/hr5LKXDkJl12WNY6hvA2El+Fmdc4poJwBRTJ1upb
|
||||
h+cGW/TBZXPirzRI1gicx4Qv++4Tv+GADpUAciOL8qXPklux5A8+cWCdOXHsb4sQ
|
||||
rRILZ0INclZma1hmyMQYL5bfGqTpvNmoJbx4jiLuJTkIcIiCO0VR+A0Rd7l0bg/S
|
||||
gzPuCK0/iSCB9QtctjVjsGF9XZut2xS/op8i0rz7UQKBgQDQ47Mp+dsHFLM3g/hw
|
||||
s8loOcLDS0oRqTyg5NRWyAg6cuTTGs/RvEb77R2RTwok5l2+XcCR/WTc6f+cW3M/
|
||||
XcDFaeXiStur1tnLr5d10twfdZE4C6xBujGAAt4pFUaerc76jb0HfUJDaANYlZIh
|
||||
5p9nwuFGlYhFckBt4YuZek9omQKBgQC7x4R06PyIka7hrkUwLtDRMTgmi2OWP0Fv
|
||||
rPQYLRKqL40Io/lI5VEpfQdgTI0k0YO92QsnvFqJBL+7qW3iPrqKAIMILiu37MNE
|
||||
t65U4U7wzJRd7b2e33Fx6VWMOVbwvmEACoBTN+p8d/WJgg5FZ2wXo6GFWOQofOiI
|
||||
0QhBkvdbMQKBgQCwjCI7Ef96ZpZqD1IE/w701gy0PoflkWG6omyMxBegPscDXR/U
|
||||
JgrglbFtxJ3QPhtw74/4U2/R/ruZDPnEzppEv5IZxicPf1Eog8nBPWvp8tW/xq3a
|
||||
B2IazVGy61Z6em/695ySHd3JVrmtPwz5Ng/4BI+dtngsKbompH/2QZen0QKBgGWZ
|
||||
PuaOhMxTnn6G7vJx8hOtgMcCFgDd+sa0mmFWScoA7lrldWRmhrJe7pXA9YEdRx16
|
||||
CJoYRBfslNyxgD2wWPd/7WWIrajXFpPgmhdczHxnBEOJ9VW3accLS3kSMSMSrqL6
|
||||
C5J7J4ju0s/yqUwN+CMWKrdecBwj8SDNkJ0CKomRAoGAKUinXQmfvvJaSWe/dtBq
|
||||
4Y97Q0vqFEZBDlE5WMYgnAVfnntdLfyMFcjvzVQksKrQWBIBCMboyhPABBdq7i9Y
|
||||
X4g2czz9mQBgQdUoJ/Co2QBUaB3IqHnP7GbUuPjJ1kBv3xAh9MFBjdrD+sxfB0C7
|
||||
NxT13TVPl8DrpE219OeBT8w=
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8W5CI2Ec5xdLw
|
||||
szPxOnvoEijr5lm3K2GFwNoRWyugFYYrrc6oPz09OCDh33ROjpNwwZdlcll74mJ9
|
||||
awHkWj6xR/B06hZDeE0p9Zp0quRmzjF2H9XTmEnhUC5qP17ab3fsZASwr2hsb0xC
|
||||
dhlKVw4MJi0jKcz8hWY2vbsj6zl+yk/SZkz7xfeaCOlBLBShvnMySXxnOyQlq7ah
|
||||
joiaEjp8s3ECKxLfC79qSkRW0ojcryLB732g8M7rG4d645CHQvoNsF2likXuM86R
|
||||
qHzMFA1+4Q1oJyNPEja3CtI3Rgu4ixB+IQptSrwM7lpGeD2zCzUNM2V/0DK9I9h+
|
||||
SLM200dbAgMBAAECggEACUarHgokq9QxuLfikXkzW/D1AfUUqwAga+Fc++jVA6u7
|
||||
sU/8cu22Wtr2R5llFW9RFIb8KTtR69dwyUNpUvEc0Ec+MMvMb+MvTacyRZea6vMx
|
||||
nWMg+SwxSz7TIllflvtRWRtt3bOtvVVX2JgPU8lowDFrHKW02iTJrV13p2Owr606
|
||||
TUt0xq8xvnqWdmIl/xdGSgmb0PfdsWKLpwCVpJI6KZj2hQGffWhU/A3zNHNjGMfG
|
||||
lRv3LEcqlsL/5+sYp5bOigk9fPMdrQ9eDJFvT5mas2mJt/YOUgefhy7quyyjuWEC
|
||||
aT5QuYLEytCYrHKvdMowBznLjdcRtkDfYXOTtwtLfQKBgQDl+N7b28En4mD4Y9xE
|
||||
N7pwQH+tjchtb/nSHmgXdvghiozBrvpg5tTujIPBJeZJdra6E8tNhSvafnsSPQbn
|
||||
E3n2C3mqfUjR2/BVMYV9IQRhlxgvtMhLzsD2Oe7kbHl+aPiku3UZkWel+8CjeO4w
|
||||
/3bzfHQB4jCPX0DjzcfEUvKSRwKBgQDRrPipyXH1idzuIVuuhrUZaA9hvawWd32K
|
||||
IBAQCgILomL1IKcydoDJ71mCKvd3qVJd5u3zkbp+zQf+qs44Xofsvb1hZ5VIbqqA
|
||||
APS53YOwvhV6J/yBHeNFvTPjynPNhH+Zd6h+N9FLezxttR7RnHxvdTz3sT6/JGnn
|
||||
xkem8FR4TQKBgAbqlDFCi62aZlYyEqbOkkHb/rsGf5ei/X1vQqwp/M5tb0xH6enO
|
||||
J2tBOJkvfZyKAHbaL4wWTDpXAXaL9VAvysQ2liMlf3IoTjMRuTUJMCuLMsQEiN2W
|
||||
y0Dcfy3JgWHm4Et8A8qQD/DzAFkqQuegV0B9ZrPDzLgTIk13m+FwqTDzAoGBAKnU
|
||||
u7jyhM6H8x4igNs1GxzQD51wfyHXeSTW4YvMP2njBtpbr3GNULW/m7V2TelriV6r
|
||||
vNLLl847Dh21hcFcuCYGbY2m0+DOWmXB4Hdnt9IBtO2z069VYQ/Mt2nrQq8VgjDx
|
||||
HdXWKj1EPWbzDFplsNiqkk5iD1vNB8cG8GSERzcFAoGAZprGJIfgEDkDX4lFpkkp
|
||||
6NvUWxrZptebuVwm0hhPlXeb+p2myZtLUo/ID2S7iopb3eylSmZkOws0H54xsvc8
|
||||
PguW+Vfc/bPqiejOPj+n2gKVw+1dBEsdGVV997fpCTXwNpjH9B6FJ4K4pEu0llcG
|
||||
5q5M4KoybB6KWSeawgGrYZ4=
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
1
common/src/mock_certificates/sha1_rsa_2048/mock_csca.srl
Normal file
1
common/src/mock_certificates/sha1_rsa_2048/mock_csca.srl
Normal file
@@ -0,0 +1 @@
|
||||
4F01DA0921B4CC5D5073BCC7F5CACFD12A6A4883
|
||||
@@ -1,18 +1,18 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC9zCCAd+gAwIBAgIUNOzWgMvjFClqJXtzixwFryngrG8wDQYJKoZIhvcNAQEF
|
||||
BQAwFDESMBAGA1UEAwwJbW9ja19jc2NhMB4XDTI0MDYyODEzNDU1NloXDTI1MDYy
|
||||
ODEzNDU1NlowEzERMA8GA1UEAwwIbW9ja19kc2MwggEiMA0GCSqGSIb3DQEBAQUA
|
||||
A4IBDwAwggEKAoIBAQDMk6l4jst9VsRv1lLb8c88pqz6KJw932Tg11S2t9cB0r4b
|
||||
NPFjEiLZGfjWgIvGpO3Qj6lFjdDXUKZWNgshJFt9It3fNVyzPU73/TCqyFIJCRw5
|
||||
Olv/Rbn5lfKUuSY/sK+0v7WdAq9zVhflrccL2LcsZ6gw4Is4ZTzS2lDHVRrjLyXE
|
||||
GO9OhKdbumVZsods6Gh3fb9jiQ9p0HDYLphfgBWutl/CSEBxCMcnezebmwYU+/MQ
|
||||
0CCetSQQ6VOsM1s9y5S9ZJcA7mDPhUrCYU7yPZnL0r2ciecq6TKJGJIzFxBcoRLq
|
||||
xAfxMoh/Ahrekw8c+ZMptgstUDYDsFQZybt1QfebAgMBAAGjQjBAMB0GA1UdDgQW
|
||||
BBQOnxkKKSWjKiTmM6OdASuguBVXYTAfBgNVHSMEGDAWgBR1NbE8sfCurS66oUXy
|
||||
PMZzVA8s6DANBgkqhkiG9w0BAQUFAAOCAQEAj02C0TIH6UVrwbU7SKl3XcaEjxJc
|
||||
2FZ2oljdCaKkNKuBNKvfp9faf99WeGBdpcgFpdi01R5KuY5Nxla7mRX+Ui3nLr3o
|
||||
liedieUn11Vg2XM73aoF7FrhM/DnLrgrd8fOfp6IPxXCK935m5F2Yp2v2xf7xlKo
|
||||
rDIGzX44gmTYs3tlGdhf1+/zxXmY9KLNP/vdFze8SUYizlci/nRVOmxFkH20pWd5
|
||||
0p9dgtebMBDmT7WB5mzfCqg8AOHxLDrl5s6AYya/MfvfnqunpOaBgd4+U1Z6ukx2
|
||||
v7oH6bR2gKuuvX6Ceg6bqroNnT2kUwugyEafeZnLGPmLGUZrC7sJrBxerA==
|
||||
MIIC9zCCAd+gAwIBAgIUTwHaCSG0zF1Qc7zH9crP0SpqSIMwDQYJKoZIhvcNAQEF
|
||||
BQAwFDESMBAGA1UEAwwJTW9jayBDU0NBMB4XDTI0MDcxMjE3NDIyM1oXDTI5MDcx
|
||||
MTE3NDIyM1owEzERMA8GA1UEAwwITW9jayBEU0MwggEiMA0GCSqGSIb3DQEBAQUA
|
||||
A4IBDwAwggEKAoIBAQDNAbRAvBrCOUcQpP7wrJ5faC7qxNq14sBfP6K2G7Tpj4Bg
|
||||
eTkCgMAcOl4Ue1M+zhtYRo3pTnidLOvcy07lX1QMV1jwo/RLZYCVQoyqW/Lqm8Kv
|
||||
VXOOJrAzkdowcyOaOLxFyWIoaWj9ZSuPuzVntWA5n7u5MT1mYVO1sq27pXpp1Cwg
|
||||
DYifSLIcn3uKXGPy1CxlxUj/B3/3T0IrOEQkXqXJe7BMg1ijbjbJYoPK2Zoc10vP
|
||||
bgdOXY/MwE6YxhpVo8Lzzq9E31kIq7Ovjrb6xT+kktSbXINX/3Htu8ELe6OuxAw+
|
||||
27CwaS/aCK/MJnHtRFzLyKvhsBf6BEq6ZgUSUfTVAgMBAAGjQjBAMB0GA1UdDgQW
|
||||
BBQ5+4AMcFOfsD0ucPu3LnUceyEJhjAfBgNVHSMEGDAWgBTXrMk+zzG6vAtACgeI
|
||||
M65Sv46adDANBgkqhkiG9w0BAQUFAAOCAQEAMh6doVDMhOZObgKi9bgJibZuOks7
|
||||
fYWu1Zi4zOc2e5Q593Yq/+NSPB65qRixOaFSS/G1ZO6VxAu0n6redn7Ia0NLpohd
|
||||
ZOL+iNt1vNugU2Ur8FbdpbaMrNDkabWSnOiXVKJ6exXYTvdghaF3P4LkZoiutMXz
|
||||
/VJ+tmeWZzhVhTQnrN0FBxvh0wfdbbdbosVaJsyB0xTD6C3aBlUTVtxdLdf3B2CA
|
||||
N0/RDh6kwOOv9mcyF9u/z/YxiZB23csSJyLMmUl9WV2xPCgSZi3A1sZqOU5IIqO3
|
||||
U4o97Nxcwj51Bm6x5Km/6/CbnXXRo+x+nHgAgYwMn42r4BrLFoDLUn9YRw==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
15
common/src/mock_certificates/sha1_rsa_2048/mock_dsc.csr
Normal file
15
common/src/mock_certificates/sha1_rsa_2048/mock_dsc.csr
Normal file
@@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICWDCCAUACAQAwEzERMA8GA1UEAwwITW9jayBEU0MwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQDNAbRAvBrCOUcQpP7wrJ5faC7qxNq14sBfP6K2G7Tp
|
||||
j4BgeTkCgMAcOl4Ue1M+zhtYRo3pTnidLOvcy07lX1QMV1jwo/RLZYCVQoyqW/Lq
|
||||
m8KvVXOOJrAzkdowcyOaOLxFyWIoaWj9ZSuPuzVntWA5n7u5MT1mYVO1sq27pXpp
|
||||
1CwgDYifSLIcn3uKXGPy1CxlxUj/B3/3T0IrOEQkXqXJe7BMg1ijbjbJYoPK2Zoc
|
||||
10vPbgdOXY/MwE6YxhpVo8Lzzq9E31kIq7Ovjrb6xT+kktSbXINX/3Htu8ELe6Ou
|
||||
xAw+27CwaS/aCK/MJnHtRFzLyKvhsBf6BEq6ZgUSUfTVAgMBAAGgADANBgkqhkiG
|
||||
9w0BAQsFAAOCAQEAXrunn244+vrEniiMFJ7si14YfKtnsE3goLAewViTfQHYkf/3
|
||||
3v4rjYW0uWBjNVpgtLXAFcg2tl/xi0olngiITyj6f4CNWaoZdGTZ1HpeSAKKf/qR
|
||||
jx8l09BnLp90xNTZOxjQNDGsnNs6Qx0D/jHEVk2ZeLy84clalIp7Y9VEvULR6uGt
|
||||
PQrZSjNvzbseKA7UmFELak+6SotP9iG25UmaEB2V2XHZmMY5wiS9TjVqrSzpaTrt
|
||||
B4A5aslqcpaWtXchX+Udg90c6aqFosAxfURbYW8Eq6FtU/PMbxZmIhdSW6tmmcCp
|
||||
ee72V7kOyRp/GXAzlf2mjefkiOv0jbFlTpEBUg==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -1,28 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDMk6l4jst9VsRv
|
||||
1lLb8c88pqz6KJw932Tg11S2t9cB0r4bNPFjEiLZGfjWgIvGpO3Qj6lFjdDXUKZW
|
||||
NgshJFt9It3fNVyzPU73/TCqyFIJCRw5Olv/Rbn5lfKUuSY/sK+0v7WdAq9zVhfl
|
||||
rccL2LcsZ6gw4Is4ZTzS2lDHVRrjLyXEGO9OhKdbumVZsods6Gh3fb9jiQ9p0HDY
|
||||
LphfgBWutl/CSEBxCMcnezebmwYU+/MQ0CCetSQQ6VOsM1s9y5S9ZJcA7mDPhUrC
|
||||
YU7yPZnL0r2ciecq6TKJGJIzFxBcoRLqxAfxMoh/Ahrekw8c+ZMptgstUDYDsFQZ
|
||||
ybt1QfebAgMBAAECggEAOj8ao+goOO4Q7PS9T8En65FbM7iHT7iArOGyTXnHXk4F
|
||||
8ZIf3kDGKkEST+R2p57C1TxqChMoMH3WdjpZ7dw/rj/Uox464A+nIcV1a1KwxMDS
|
||||
x9p9Yg+UtWLDmCOlJ8IjLNfemi8vDCwpjqvtPcq80IhM42mzSeHNMQ2WrUJmbuM1
|
||||
0H8bFCRA1orqSYJz4tBVhlwtcEZFDstWgXZQ26kXkXcTtJVjfaJTAg6qwErsCUr8
|
||||
hn6j3fzqOyhHqx2vHyvZns+ARchWHuMLQ5KLP16ijvDXuVHCMGv5FJT1CtUDG6n0
|
||||
SY4nooaSviJoNJB2gg36KqUUwoGxMoGnreIAOIfH4QKBgQDmMXYfFGcBbWYRKX1D
|
||||
ClaHfUlFR/7rZXhlVmKLgHMBR+OqCiqZbvorUbVAxpXw4IH+GNx695OqiQhLUOY7
|
||||
yICpCt6Pq8gkfLYFQiXebevxfF60OB/NrbXICYtWyzqPAclBHauS4J9tDIYHfSJo
|
||||
JD0MqJL37I0ctil0fNjmCVTJuwKBgQDjgwKxAvqvJX4En2+hrKG/aOmCXg5Wdn+3
|
||||
wHvxu/3QRQJehbq/Qcz3MDXPATqOoH86SzFfjREMpsL3+FZYlN5cWK3siNDRq+Uz
|
||||
O1JOPWB0ehMNCFX+UmaFdNfS1NB+oQ1QD+PVVRZUwDz5jdBKTXt4mtgUHbkYMFcs
|
||||
xzVOecM7oQKBgQDKtWO/msfaiewH0PFtx/zK85lCWVQzFvgexSOilUqxJg1l/+3j
|
||||
j8bdvuZOVJJVvF681EfUQZDX7DRRnrwgiUBDnD7BZhSpjOj9WHLgnQvZbBw5t/LJ
|
||||
vN8HeOArXmwC4x/HJ8mfXg8GiLC+h4N1EfRw4UIK8VSSpBd9bTPT3wO7YQKBgHvE
|
||||
FX6+JCmLt9ZD9bJ5+zPpmr409I/MvwXzTHngzt6x6+wHy+OnpB0EuQD3pidY4F2R
|
||||
8jYMw62iOoYzLqXZtm1+QH9gnlixrmoEZ23wrbwvfJWmZ0GHCgan3ZDv/MwmSNu5
|
||||
CTRQqWlJeuI3Z4xEQlsFwW6QDNU/1uyhIjqiuraBAoGACoHype8atLKYQsVMIqWE
|
||||
t8+PeLJs1OKoJFCvTPaZ4uc5hj9q/Zwm1d2lXQHEys2fNnX04szAR4CqdMA+6vpE
|
||||
pdoTmDwzpY1fjisWTZxuAKky1/MKoPx2vJefuC3P1EoLoIjOXxs8c1eIqmjtkvpr
|
||||
AG9WTDrJOYamVzCLQ9mME/g=
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDNAbRAvBrCOUcQ
|
||||
pP7wrJ5faC7qxNq14sBfP6K2G7Tpj4BgeTkCgMAcOl4Ue1M+zhtYRo3pTnidLOvc
|
||||
y07lX1QMV1jwo/RLZYCVQoyqW/Lqm8KvVXOOJrAzkdowcyOaOLxFyWIoaWj9ZSuP
|
||||
uzVntWA5n7u5MT1mYVO1sq27pXpp1CwgDYifSLIcn3uKXGPy1CxlxUj/B3/3T0Ir
|
||||
OEQkXqXJe7BMg1ijbjbJYoPK2Zoc10vPbgdOXY/MwE6YxhpVo8Lzzq9E31kIq7Ov
|
||||
jrb6xT+kktSbXINX/3Htu8ELe6OuxAw+27CwaS/aCK/MJnHtRFzLyKvhsBf6BEq6
|
||||
ZgUSUfTVAgMBAAECggEAGlxMvEIzwqOw0qAUtAfOOYBhAAkeAmNMzzKUjowTgDDW
|
||||
lhEgVoUNrtOGg2W0N5AzDe/MkaJoefVrwrFVzMKsQQX+RrseT4+WsBqlkcZO/wHW
|
||||
T8tSF4Y8A/WOM8qqWktPUj3p5D5hpKucpVeyL0qwO9ihP9foCEEdjXCTTFyj1/WY
|
||||
O7IdsKNDY+srTK73xWIEnyH+ffEKIaSu9wrntYASudllLO/PrxpxJ4M+/4/I5Cep
|
||||
PzklQhEdv/5ler0uzHGc/RtVfibjpdEDVgsere9Nq+cXf0k4JrZZ8ySy3WHgAPWG
|
||||
zWj3sduFW37Dsb/XvzuQ7oRg4v6lofaJSlaLxA2ExQKBgQD3eE75vjVQdTkKpFMQ
|
||||
c//0nLRne09VbOqPHhpkyZC9FJJ+UkIRvlNbkBtHhhNTj/u6FnkaJGS3RONeDe0o
|
||||
Q0fe16zY38q70HlulNo6h069ckhWrIA8qbrKntqxc2bVL5LDUoA/VmY5nk76L5Tu
|
||||
7b22+ipcdij2ibU+r10T5X5/0wKBgQDUErJVj/dm52QI039VPyl1wMjGDeUvWZxs
|
||||
8iT9FT58Kp/E/+fiZ8JbFqJyWSpEm5rZyK5P40USN1r/B2EdxHSyete52sko8Huh
|
||||
Jku4DVStyIzq63d3gEpIqfb2rmMUlc707bNqdgOX4IZ8RYxFgnp2AB5X8e/LyHZR
|
||||
nSFdADD3twKBgHw8PMGqGM/UmZdbGYxH//ZIeVT+FbzYGgVRYoS4oF4cJtMd7qdD
|
||||
uktcVCWbDLbFsOUiBRf3r0xGXDLKoQW2iS05bz/NUdTp+xxlxAzgAsqexewlW5eY
|
||||
yfqQt0+glL5vzKkcEOA7OsSwUgvNuWIdnkFu47dZZoUmawQWO48ShmgbAoGBAKlz
|
||||
3wc7J8YTsfzTcfUdqPUr+8E1LSGuiq0Ktr96kBkKverdR93CZqv95ANWd82mQA8w
|
||||
qQewY2pwzMbmkJUGevB585HP3dhWf5J+VRZVoInTq7WyPB1CZxi0pl7pbMXwBhPz
|
||||
Mt8oOSrL/umhcLnBzjQnWBeRe7frD4+a7COxmW71AoGBAO0yhYXOeHpGTnHzDzTs
|
||||
qu3rNhvQKy/8f25wvqn/xR5NfbcQv/Z63PgmDoq9VLrmeektwY4zTE9wO+n7WPQU
|
||||
D2BiW2DQjX4OJsOPNs63+wCE71xj08ZxipFuxFWhbjtO/A82h6QMXYwfj9do1WGD
|
||||
oouEG7wJwn8++cuiivyeTWf1
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
@@ -91,4 +91,26 @@ export function readCertificate(filePath: string): jsrsasign.X509 {
|
||||
const certificate = new jsrsasign.X509();
|
||||
certificate.readCertPEM(certPem);
|
||||
return certificate;
|
||||
}
|
||||
|
||||
export function getTBSCertificate(certificate: jsrsasign.X509): Buffer {
|
||||
// console.log("Certificate:", certificate);
|
||||
|
||||
const certASN1 = certificate.getParam();
|
||||
// console.log("certASN1:", certASN1);
|
||||
|
||||
if (!certASN1) {
|
||||
console.error("Failed to get certificate parameters");
|
||||
throw new Error("Invalid certificate structure");
|
||||
}
|
||||
|
||||
// Extract the TBS part directly from the certificate's hex representation
|
||||
const certHex = certificate.hex;
|
||||
const tbsStartIndex = certHex.indexOf('30') + 2; // Start after the first sequence tag
|
||||
const tbsLength = parseInt(certHex.substr(tbsStartIndex, 2), 16) * 2 + 2; // Length in bytes * 2 for hex + 2 for length field
|
||||
const tbsHex = certHex.substr(tbsStartIndex - 2, tbsLength); // Include the sequence tag
|
||||
|
||||
// console.log("TBS Hex:", tbsHex);
|
||||
|
||||
return Buffer.from(tbsHex, 'hex');
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { CSCA_AKI_MODULUS, CSCA_TREE_DEPTH } from "../constants/constants";
|
||||
import { poseidon16, poseidon2, poseidon4 } from "poseidon-lite";
|
||||
import { IMT } from "@zk-kit/imt";
|
||||
import serialized_csca_tree from "../../pubkeys/serialized_csca_tree.json"
|
||||
import { createHash } from "crypto";
|
||||
|
||||
export function findStartIndex(modulus: string, messagePadded: Uint8Array): number {
|
||||
const modulusNumArray = [];
|
||||
@@ -44,8 +45,12 @@ export function getCSCAInputs(dscSecret: string, dscCertificate: any, cscaCertif
|
||||
if (devmod) {
|
||||
console.log('DEV MODE');
|
||||
//const csca_modulus_bigint = BigInt('0x' + csca_modulus);
|
||||
console.log("certificate", cscaCertificate);
|
||||
//console.log('csca_modulus_hex', cscaCertificate.getPublicKeyHex());
|
||||
|
||||
const rsaPublicKey = cscaCertificate.publicKey as forge.pki.rsa.PublicKey;
|
||||
const csca_modulus = rsaPublicKey.n.toString(16).toLowerCase();
|
||||
console.log('csca_modulus', csca_modulus);
|
||||
csca_modulus_bigint = BigInt(`0x${csca_modulus}`);
|
||||
csca_modulus_formatted = splitToWords(csca_modulus_bigint, BigInt(n_csca), BigInt(k_csca));
|
||||
console.log('csca_modulus_formatted', csca_modulus_formatted);
|
||||
@@ -105,6 +110,11 @@ export function getCSCAInputs(dscSecret: string, dscCertificate: any, cscaCertif
|
||||
else if (signatureAlgorithm === '1.2.840.113549.1.1.11') { //sha256
|
||||
[dsc_message_padded, dsc_messagePaddedLen] = sha256Pad(dsc_tbsCertificateUint8Array, max_cert_bytes);
|
||||
}
|
||||
else {
|
||||
console.log("Signature algorithm not recognized", signatureAlgorithm);
|
||||
[dsc_message_padded, dsc_messagePaddedLen] = sha256Pad(dsc_tbsCertificateUint8Array, max_cert_bytes);
|
||||
|
||||
}
|
||||
const startIndex = findStartIndex(dsc_modulus, dsc_message_padded);
|
||||
const startIndex_formatted = startIndex.toString();
|
||||
const dsc_message_padded_formatted = Array.from(dsc_message_padded).map((x) => x.toString())
|
||||
@@ -206,5 +216,18 @@ export function getCSCAModulusProof(leaf, n, k) {
|
||||
return [tree.root, proof];
|
||||
}
|
||||
|
||||
export function getTBSHash(cert: forge.pki.Certificate, hashAlgorithm: 'sha1' | 'sha256'): string[] {
|
||||
const tbsCertAsn1 = forge.pki.certificateToAsn1(cert).value[0];
|
||||
const tbsCertDer = forge.asn1.toDer(tbsCertAsn1 as any).getBytes();
|
||||
const md = hashAlgorithm === 'sha256' ? forge.md.sha256.create() : forge.md.sha1.create();
|
||||
md.update(tbsCertDer);
|
||||
const tbsCertificateHash = md.digest();
|
||||
const tbsCertificateHashString = tbsCertificateHash.data;
|
||||
const tbsCertificateHashHex = Buffer.from(tbsCertificateHashString, 'binary').toString('hex');
|
||||
const tbsCertificateHashBigint = BigInt(`0x${tbsCertificateHashHex}`);
|
||||
console.log('tbsCertificateHashBigint', tbsCertificateHashBigint);
|
||||
return splitToWords(tbsCertificateHashBigint, BigInt(64), BigInt(32));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -634,41 +634,41 @@ export const mockPassportData_sha1WithRSAEncryption_65537 = {
|
||||
"mrz": "P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02",
|
||||
"signatureAlgorithm": "sha1WithRSAEncryption",
|
||||
"pubKey": {
|
||||
"modulus": "22480969390802826527612289605322373709607796204484082125179082202842187594030746274096990975473157470353260434866140253775617322614317842584277684263273085398758828719210973208632246906520027587934588291311922909505699040207707335541543985272384000014886820430286901756121253512285729673528629390257652494355569005906835585173481884916905337685920438573395012275370654528706928278300240972594792647459747106552104398149544784541159688532413072278844759518831349873260668156132419311110193685220374735679580093984854335187305593318372186076577084719489194525709637470310818679179550246249200552494360645496955029908931",
|
||||
"modulus": "25825429057059192136108879878584777378654757240338449850333826035522788688006003098652086918620774520803490546755795078682140839966138109158244063837927200135790195224745239859057220329386561601721351696226057564841628462419818778146307352956712449575319326790354320318538693617555205343313027743984395735323775616464067940972666996572033472954611814220870194705592266623708066532169995623347732878333242475140240755230523341780618713394357686812647104201915704768910310961389728873036708721827192621939370755343467271300872482189554492692990185310969209988312747691889806959985764889980641836439721025225230179760027",
|
||||
"exponent": "65537"
|
||||
},
|
||||
"dataGroupHashes": [
|
||||
-31,
|
||||
-62,
|
||||
104,
|
||||
-64,
|
||||
-48,
|
||||
18,
|
||||
27,
|
||||
-5,
|
||||
-7,
|
||||
21,
|
||||
125,
|
||||
26,
|
||||
-46,
|
||||
-69,
|
||||
-48,
|
||||
30,
|
||||
-72,
|
||||
-105,
|
||||
104,
|
||||
58,
|
||||
-127,
|
||||
-82,
|
||||
12,
|
||||
-127,
|
||||
-122,
|
||||
96,
|
||||
100,
|
||||
24,
|
||||
117,
|
||||
-114,
|
||||
37,
|
||||
-38,
|
||||
-53,
|
||||
-28,
|
||||
-75,
|
||||
9,
|
||||
105,
|
||||
-62,
|
||||
-46,
|
||||
-40,
|
||||
115,
|
||||
-43,
|
||||
29,
|
||||
31,
|
||||
-120,
|
||||
0,
|
||||
55,
|
||||
123,
|
||||
95,
|
||||
-5,
|
||||
-51,
|
||||
-36,
|
||||
-14,
|
||||
-55,
|
||||
-81,
|
||||
-64,
|
||||
72,
|
||||
76,
|
||||
1,
|
||||
50,
|
||||
-96,
|
||||
114,
|
||||
-93,
|
||||
@@ -823,284 +823,284 @@ export const mockPassportData_sha1WithRSAEncryption_65537 = {
|
||||
34,
|
||||
4,
|
||||
32,
|
||||
-110,
|
||||
20,
|
||||
-102,
|
||||
-44,
|
||||
16,
|
||||
-39,
|
||||
107,
|
||||
108,
|
||||
84,
|
||||
50,
|
||||
-21,
|
||||
-116,
|
||||
-87,
|
||||
-49,
|
||||
5,
|
||||
93,
|
||||
-1,
|
||||
58,
|
||||
-111,
|
||||
1,
|
||||
94,
|
||||
-94,
|
||||
0,
|
||||
-44,
|
||||
-10,
|
||||
92,
|
||||
-28
|
||||
45,
|
||||
51,
|
||||
-75,
|
||||
9,
|
||||
107,
|
||||
0,
|
||||
93,
|
||||
73,
|
||||
104,
|
||||
-127,
|
||||
-71
|
||||
],
|
||||
"encryptedDigest": [
|
||||
67,
|
||||
155,
|
||||
237,
|
||||
112,
|
||||
248,
|
||||
146,
|
||||
216,
|
||||
126,
|
||||
42,
|
||||
186,
|
||||
213,
|
||||
89,
|
||||
48,
|
||||
103,
|
||||
191,
|
||||
192,
|
||||
32,
|
||||
176,
|
||||
46,
|
||||
109,
|
||||
111,
|
||||
67,
|
||||
91,
|
||||
160,
|
||||
195,
|
||||
150,
|
||||
60,
|
||||
147,
|
||||
128,
|
||||
218,
|
||||
108,
|
||||
51,
|
||||
142,
|
||||
24,
|
||||
201,
|
||||
225,
|
||||
218,
|
||||
137,
|
||||
57,
|
||||
75,
|
||||
102,
|
||||
20,
|
||||
66,
|
||||
168,
|
||||
4,
|
||||
97,
|
||||
54,
|
||||
26,
|
||||
195,
|
||||
211,
|
||||
62,
|
||||
195,
|
||||
80,
|
||||
212,
|
||||
18,
|
||||
58,
|
||||
142,
|
||||
82,
|
||||
186,
|
||||
15,
|
||||
175,
|
||||
188,
|
||||
201,
|
||||
62,
|
||||
203,
|
||||
25,
|
||||
98,
|
||||
232,
|
||||
212,
|
||||
24,
|
||||
166,
|
||||
248,
|
||||
52,
|
||||
194,
|
||||
23,
|
||||
202,
|
||||
253,
|
||||
117,
|
||||
248,
|
||||
7,
|
||||
38,
|
||||
34,
|
||||
6,
|
||||
167,
|
||||
61,
|
||||
254,
|
||||
213,
|
||||
111,
|
||||
35,
|
||||
61,
|
||||
97,
|
||||
174,
|
||||
91,
|
||||
68,
|
||||
128,
|
||||
82,
|
||||
90,
|
||||
75,
|
||||
125,
|
||||
170,
|
||||
7,
|
||||
5,
|
||||
38,
|
||||
227,
|
||||
175,
|
||||
176,
|
||||
1,
|
||||
223,
|
||||
90,
|
||||
255,
|
||||
205,
|
||||
79,
|
||||
29,
|
||||
132,
|
||||
151,
|
||||
35,
|
||||
92,
|
||||
61,
|
||||
48,
|
||||
156,
|
||||
40,
|
||||
135,
|
||||
179,
|
||||
20,
|
||||
250,
|
||||
169,
|
||||
0,
|
||||
76,
|
||||
115,
|
||||
46,
|
||||
253,
|
||||
176,
|
||||
244,
|
||||
162,
|
||||
245,
|
||||
22,
|
||||
247,
|
||||
166,
|
||||
51,
|
||||
90,
|
||||
99,
|
||||
44,
|
||||
197,
|
||||
6,
|
||||
63,
|
||||
188,
|
||||
4,
|
||||
9,
|
||||
245,
|
||||
124,
|
||||
114,
|
||||
239,
|
||||
29,
|
||||
170,
|
||||
153,
|
||||
142,
|
||||
169,
|
||||
43,
|
||||
85,
|
||||
234,
|
||||
203,
|
||||
220,
|
||||
110,
|
||||
16,
|
||||
109,
|
||||
189,
|
||||
63,
|
||||
157,
|
||||
249,
|
||||
201,
|
||||
109,
|
||||
83,
|
||||
251,
|
||||
142,
|
||||
35,
|
||||
5,
|
||||
211,
|
||||
60,
|
||||
126,
|
||||
28,
|
||||
28,
|
||||
30,
|
||||
205,
|
||||
18,
|
||||
237,
|
||||
131,
|
||||
129,
|
||||
223,
|
||||
63,
|
||||
83,
|
||||
61,
|
||||
100,
|
||||
85,
|
||||
90,
|
||||
167,
|
||||
46,
|
||||
180,
|
||||
52,
|
||||
145,
|
||||
184,
|
||||
97,
|
||||
2,
|
||||
111,
|
||||
162,
|
||||
47,
|
||||
21,
|
||||
106,
|
||||
219,
|
||||
170,
|
||||
210,
|
||||
33,
|
||||
66,
|
||||
163,
|
||||
144,
|
||||
138,
|
||||
46,
|
||||
108,
|
||||
25,
|
||||
11,
|
||||
222,
|
||||
64,
|
||||
97,
|
||||
21,
|
||||
28,
|
||||
113,
|
||||
200,
|
||||
170,
|
||||
83,
|
||||
156,
|
||||
16,
|
||||
31,
|
||||
48,
|
||||
4,
|
||||
210,
|
||||
158,
|
||||
145,
|
||||
129,
|
||||
189,
|
||||
133,
|
||||
48,
|
||||
174,
|
||||
175,
|
||||
182,
|
||||
229,
|
||||
3,
|
||||
156,
|
||||
166,
|
||||
114,
|
||||
195,
|
||||
60,
|
||||
219,
|
||||
127,
|
||||
8,
|
||||
214,
|
||||
77,
|
||||
213,
|
||||
245,
|
||||
177,
|
||||
130,
|
||||
237,
|
||||
4,
|
||||
44,
|
||||
87,
|
||||
28,
|
||||
70,
|
||||
24,
|
||||
248,
|
||||
5,
|
||||
240,
|
||||
162,
|
||||
234,
|
||||
93,
|
||||
62,
|
||||
124,
|
||||
109,
|
||||
165,
|
||||
227,
|
||||
92,
|
||||
71,
|
||||
199,
|
||||
101,
|
||||
98,
|
||||
15,
|
||||
132,
|
||||
23,
|
||||
191,
|
||||
36,
|
||||
158,
|
||||
211,
|
||||
56,
|
||||
127,
|
||||
72,
|
||||
134,
|
||||
133,
|
||||
217,
|
||||
210,
|
||||
217,
|
||||
34,
|
||||
3,
|
||||
77,
|
||||
16,
|
||||
139,
|
||||
55,
|
||||
25,
|
||||
8,
|
||||
83,
|
||||
161,
|
||||
2,
|
||||
179,
|
||||
201,
|
||||
57,
|
||||
19,
|
||||
233,
|
||||
67,
|
||||
225,
|
||||
54,
|
||||
195,
|
||||
226,
|
||||
16,
|
||||
22,
|
||||
130,
|
||||
96,
|
||||
18,
|
||||
206,
|
||||
170,
|
||||
208,
|
||||
171,
|
||||
126,
|
||||
180,
|
||||
137,
|
||||
62,
|
||||
195,
|
||||
226,
|
||||
206,
|
||||
111,
|
||||
82,
|
||||
171,
|
||||
199,
|
||||
128,
|
||||
147,
|
||||
186
|
||||
156,
|
||||
156,
|
||||
32,
|
||||
5,
|
||||
175,
|
||||
187,
|
||||
135,
|
||||
227,
|
||||
51,
|
||||
0,
|
||||
228,
|
||||
175,
|
||||
251,
|
||||
2,
|
||||
231,
|
||||
85,
|
||||
168,
|
||||
160,
|
||||
9,
|
||||
133,
|
||||
158,
|
||||
175,
|
||||
135,
|
||||
42,
|
||||
59,
|
||||
13,
|
||||
113,
|
||||
211,
|
||||
132,
|
||||
92,
|
||||
140,
|
||||
106,
|
||||
36,
|
||||
191,
|
||||
109,
|
||||
213,
|
||||
214,
|
||||
57,
|
||||
76,
|
||||
35,
|
||||
132,
|
||||
176,
|
||||
116,
|
||||
130,
|
||||
212,
|
||||
101,
|
||||
115,
|
||||
28,
|
||||
116,
|
||||
203,
|
||||
9,
|
||||
98,
|
||||
10,
|
||||
68,
|
||||
219,
|
||||
128,
|
||||
68,
|
||||
110,
|
||||
177,
|
||||
175,
|
||||
210,
|
||||
80,
|
||||
144,
|
||||
65,
|
||||
236,
|
||||
128,
|
||||
249,
|
||||
219,
|
||||
189,
|
||||
216,
|
||||
36,
|
||||
234,
|
||||
61,
|
||||
75,
|
||||
53,
|
||||
101,
|
||||
224,
|
||||
126,
|
||||
82,
|
||||
207,
|
||||
65,
|
||||
182,
|
||||
254,
|
||||
133,
|
||||
251,
|
||||
103,
|
||||
219,
|
||||
207,
|
||||
17,
|
||||
172,
|
||||
26,
|
||||
139,
|
||||
120,
|
||||
184,
|
||||
183,
|
||||
176,
|
||||
192,
|
||||
102,
|
||||
19,
|
||||
184,
|
||||
252,
|
||||
146,
|
||||
175,
|
||||
169,
|
||||
252,
|
||||
3,
|
||||
170,
|
||||
141,
|
||||
13,
|
||||
136,
|
||||
248,
|
||||
94,
|
||||
237,
|
||||
158,
|
||||
114,
|
||||
149,
|
||||
155,
|
||||
241,
|
||||
169,
|
||||
161,
|
||||
99,
|
||||
239,
|
||||
55,
|
||||
30,
|
||||
125,
|
||||
219,
|
||||
65,
|
||||
43,
|
||||
64,
|
||||
12,
|
||||
243,
|
||||
138,
|
||||
114,
|
||||
150,
|
||||
32,
|
||||
165,
|
||||
220,
|
||||
91,
|
||||
199,
|
||||
176,
|
||||
30,
|
||||
156,
|
||||
10,
|
||||
199,
|
||||
196,
|
||||
152,
|
||||
4,
|
||||
194,
|
||||
145,
|
||||
163,
|
||||
66,
|
||||
212,
|
||||
239,
|
||||
164,
|
||||
248,
|
||||
242,
|
||||
26,
|
||||
51,
|
||||
235,
|
||||
101,
|
||||
95,
|
||||
133,
|
||||
142,
|
||||
189,
|
||||
226,
|
||||
195
|
||||
],
|
||||
"photoBase64": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3..."
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user