Skip to content

Commit fc09fe1

Browse files
feat: support aes-256-cbc encrypted results decryption
1 parent 2959437 commit fc09fe1

11 files changed

+303
-163
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
44

55
## NEXT
66

7+
### Added
8+
9+
- added support for aes-256-cbc encrypted result decryption
10+
711
### Changed
812

913
- fixed `BN` type export issue

src/common/utils/result-utils.js

Lines changed: 72 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,17 @@ const debug = Debug('iexec:result-utils');
1010
export const decryptResult = async (encResultsZipBuffer, beneficiaryKey) => {
1111
const { CryptoKey } = await getCrypto();
1212

13-
let pemPrivateKey;
13+
let pemRsaPrivateKey;
1414
if (beneficiaryKey instanceof CryptoKey) {
15-
pemPrivateKey = await privateAsPem(beneficiaryKey);
15+
pemRsaPrivateKey = await privateAsPem(beneficiaryKey);
1616
} else {
17-
pemPrivateKey = Buffer.from(beneficiaryKey).toString();
17+
pemRsaPrivateKey = Buffer.from(beneficiaryKey).toString();
18+
}
19+
let rsaPrivateKey;
20+
try {
21+
rsaPrivateKey = forgePki.pki.privateKeyFromPem(pemRsaPrivateKey);
22+
} catch (error) {
23+
throw Error('Invalid beneficiary key', { cause: error });
1824
}
1925

2026
const ENC_KEY_FILE_NAME = 'aes-key.rsa';
@@ -85,23 +91,34 @@ export const decryptResult = async (encResultsZipBuffer, beneficiaryKey) => {
8591
);
8692
});
8793

88-
const base64encodedEncryptedAesKey = Buffer.from(
89-
encryptedResultsKeyArrayBuffer,
90-
).toString();
91-
92-
const encryptedAesKeyBuffer = Buffer.from(
93-
base64encodedEncryptedAesKey,
94-
'base64',
95-
);
96-
94+
const encryptedAesKeyBuffer = Buffer.from(encryptedResultsKeyArrayBuffer);
9795
debug('Decrypting results key');
9896
let aesKeyBuffer;
97+
const aesKeyDecryptionErrors = [];
9998
try {
100-
const key = forgePki.pki.privateKeyFromPem(pemPrivateKey);
101-
const base64EncodedResultsKey = key.decrypt(encryptedAesKeyBuffer);
102-
aesKeyBuffer = Buffer.from(base64EncodedResultsKey, 'base64');
99+
try {
100+
const resultsKey = rsaPrivateKey.decrypt(encryptedAesKeyBuffer);
101+
aesKeyBuffer = Buffer.from(resultsKey, 'binary');
102+
} catch (error) {
103+
aesKeyDecryptionErrors.push(error);
104+
debug(
105+
'standard result key decryption failed, trying base64 encoded encrypted key (legacy)',
106+
);
107+
const base64encodedEncryptedAesKey = Buffer.from(
108+
encryptedResultsKeyArrayBuffer,
109+
).toString();
110+
const encryptedAesKeyBuffer = Buffer.from(
111+
base64encodedEncryptedAesKey,
112+
'base64',
113+
);
114+
const base64EncodedResultsKey = rsaPrivateKey.decrypt(
115+
encryptedAesKeyBuffer,
116+
);
117+
aesKeyBuffer = Buffer.from(base64EncodedResultsKey, 'base64');
118+
}
103119
} catch (error) {
104-
debug(error);
120+
aesKeyDecryptionErrors.push(error);
121+
debug(`decryption errors: ${aesKeyDecryptionErrors}`);
105122
throw Error('Failed to decrypt results key with beneficiary key');
106123
}
107124

@@ -120,36 +137,55 @@ export const decryptResult = async (encResultsZipBuffer, beneficiaryKey) => {
120137
);
121138
});
122139

123-
// decrypt AES ECB (with one time AES key)
124-
debug('Decrypting results');
140+
// decrypt AES (with one time AES key)
141+
debug(`Decrypting results`);
125142
try {
126-
const base64EncodedEncryptedZip = Buffer.from(
127-
encResultsArrayBuffer,
128-
).toString();
129-
let encryptedOutZipBuffer = Buffer.from(
130-
base64EncodedEncryptedZip,
131-
'base64',
132-
);
133-
const aesEcbDecipher = forgeAes.cipher.createDecipher(
134-
'AES-ECB',
135-
forgeAes.util.createBuffer(aesKeyBuffer),
136-
);
137-
aesEcbDecipher.start();
143+
let aesDecipher;
144+
let encryptedOutZipBuffer;
145+
switch (aesKeyBuffer.byteLength * 8) {
146+
case 256:
147+
// current result encryption was based on aes-256-cbc IV is stored in the 16 first bytes of the payload
148+
debug(`aes-256-cbc mode detected`);
149+
aesDecipher = forgeAes.cipher.createDecipher(
150+
'AES-CBC',
151+
forgeAes.util.createBuffer(aesKeyBuffer),
152+
);
153+
aesDecipher.start({
154+
iv: forgeAes.util.createBuffer(encResultsArrayBuffer.slice(0, 16)),
155+
});
156+
encryptedOutZipBuffer = Buffer.from(encResultsArrayBuffer.slice(16));
157+
break;
158+
case 128:
159+
// legacy result encryption was based on aes-128-ecb with aes encrypted payload encoded in base64
160+
debug(`Legacy mode aes-128-ecb mode detected`);
161+
aesDecipher = forgeAes.cipher.createDecipher(
162+
'AES-ECB',
163+
forgeAes.util.createBuffer(aesKeyBuffer),
164+
);
165+
aesDecipher.start();
166+
encryptedOutZipBuffer = Buffer.from(
167+
Buffer.from(encResultsArrayBuffer).toString(),
168+
'base64',
169+
);
170+
break;
171+
default:
172+
throw Error('Failed to determine result encryption mode');
173+
}
138174

139175
const CHUNK_SIZE = 10 * 1000 * 1000;
140176
let decryptionBuffer = Buffer.from([]);
141177
while (encryptedOutZipBuffer.byteLength > 0) {
142178
// flush cipher buffer
143-
const tmpBuffer = Buffer.from(aesEcbDecipher.output.getBytes(), 'binary');
179+
const tmpBuffer = Buffer.from(aesDecipher.output.getBytes(), 'binary');
144180
decryptionBuffer = Buffer.concat([decryptionBuffer, tmpBuffer]);
145181
// process chunk
146-
const chunk = encryptedOutZipBuffer.slice(0, CHUNK_SIZE);
147-
encryptedOutZipBuffer = encryptedOutZipBuffer.slice(CHUNK_SIZE);
148-
aesEcbDecipher.update(forgeAes.util.createBuffer(chunk));
182+
const chunk = encryptedOutZipBuffer.subarray(0, CHUNK_SIZE);
183+
encryptedOutZipBuffer = encryptedOutZipBuffer.subarray(CHUNK_SIZE);
184+
aesDecipher.update(forgeAes.util.createBuffer(chunk));
149185
}
150-
aesEcbDecipher.finish();
186+
aesDecipher.finish();
151187
const finalizationBuffer = Buffer.from(
152-
aesEcbDecipher.output.getBytes(),
188+
aesDecipher.output.getBytes(),
153189
'binary',
154190
);
155191
return Buffer.concat([decryptionBuffer, finalizationBuffer]);
Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,52 @@
11
-----BEGIN PRIVATE KEY-----
2-
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
51-
S5xNpBTrDJV5d1Qx+sCsw0ghKSNHzTS+JQ==
2+
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
51+
FVpEMFZreUZdkNwz+yLuhDRYVab5kA==
5252
-----END PRIVATE KEY-----
Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
-----BEGIN PUBLIC KEY-----
2-
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA29Y2NYC08oFJ8GxPR3dK
3-
kI+Au+6keWHZ8CXs9f54WrXlNusNqqhOH7h4fQKaNHhptqSutmo6xYwmen4eUqe6
4-
72NnmTeBpexvlHj16uDqgVoySVMaYMSwexRr+n7BQ2NWYntYc3r0ZjBACK7NMyrb
5-
fp4W5UNGKDk3pq0ukPQQ8IGAUhZPPsncVpOSq65Ks1aI1vBSM6UzHCks582H1b0N
6-
qO40vWd0Zd/8Lb/iHW6NDJXGgM0K/gRYz5hG3w0q9BvwN4mhHX1+2PWtuImv7np7
7-
CWU5edVJYQ1E5mXARLVUzYLmDXM1nvckkLVAdGOvsXv8P60z+Q2zpIvK14+xm5Cf
8-
EpAA5gOT+IQwcSOxuBstKpS8TXBXGvG8wsgJkK2docS9C8CIQU1OkI0EW4N7ViSA
9-
hH2kM6sRIN3g8nmfiiSTu1YAynaMcXe0H/0zl8fXE1c3wi2X2S/SFwxMSwPG5yTB
10-
2qLo9x75C8WUZC+uUP6VZcQE9B93F7DLzhd6O1VisGHefPQ/dF6rRreRwGI+JzL9
11-
ROsm42L6N5HwSodD4x7Hil6nw2FdgK5/RkTRa47gtTTcSKFUAFB/YivDDBhyCqSx
12-
oSEDTczO+ZMeoYGNQwiFpetTB7E4zNfxofllEvMax3/VOFurRbwDlMavD0LPeRM6
13-
MUkxe2lT4YFowUo6JCUFlPcCAwEAAQ==
2+
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq7VSumrfBbc3Qp4heLEw
3+
IZEkl5tpmcJqC8Sscr4sa1fKmQrSzqSQ/sayHtYx0Xf8BHX9HgnvxPTmMUAAOgFR
4+
fxliQt3jcipvI3EOX1e8J4ZJBSYbll3AOWfuFU80u4qpTPM03ZBoo8mDiWs7/fLO
5+
BGVotoz5n9NEgUXoNL8EZV6QpljmiCW2hjk6hdYS9tVvkIeonGAfAwzSlEuBzxn4
6+
4eysU2saPZ5ahrafIKV8qIFN2anY2sAN8BRs9956m/WUzBMSByxa2q8lgQdJ5NgM
7+
Lgu8Anr0vXgiXxLU37GZn4uSsj3m9o5sJA04tO2zay8L1kW7oXVyN+jeu1RX3izt
8+
27n+GounxLTVK+P6V7k14Pb55mvbil/NrQmJUcuBkGEluJ0WwOxLCXjPlYmmaSTK
9+
YtVf/9FsEO84Ah/v19XjF5Q+zs3yUtn0fRHogExzUXbNQXdeqWWbPUGXZ1kMVMax
10+
sZAneyE8FWfT4GXXhoN/o10uSks0jPtj4TW6X1Q2t4yFtVeNxwRT0qITL1QhjRgW
11+
sJWd8XjRci3lEgX8lUTFQ0+bdxqJ86ICIkcdJtZzwIjHTlzSGzrIdCFhty1PIlfQ
12+
fCJwZ2L6FZTE/c5buFRu1LCLQPZ3gMqqSpwjjGQ7ODA1XVWwfkgzg098I1T5G9z/
13+
z68MerLDu9AIEv0WVMX5MrECAwEAAQ==
1414
-----END PUBLIC KEY-----

0 commit comments

Comments
 (0)