Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,8 @@ export class JobService {
this.pgpConfigService.passphrase,
);

manifest = JSON.parse(await encryption.decrypt(manifestEncrypted));
const decryptedData = await encryption.decrypt(manifestEncrypted);
manifest = JSON.parse(Buffer.from(decryptedData).toString());
} catch {
throw new Error(ErrorJob.ManifestDecryptionFailed);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ export class StorageService {
this.pgpConfigService.passphrase,
);

return JSON.parse(await encryption.decrypt(fileContent)) as ISolution[];
const decryptedData = await encryption.decrypt(fileContent);
return JSON.parse(Buffer.from(decryptedData).toString()) as ISolution[];
}

return typeof fileContent == 'string'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ export class StorageService {
this.pgpConfigService.passphrase,
);

return JSON.parse(await encryption.decrypt(fileContent));
const decryptedData = await encryption.decrypt(fileContent);
return JSON.parse(Buffer.from(decryptedData).toString());
} catch {
throw new Error('Unable to decrypt manifest');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2650,9 +2650,11 @@ describe('JobService', () => {
expect(storageService.uploadFile).toHaveBeenCalled();
expect(
JSON.parse(
await encryption.decrypt(
(storageService.uploadFile as any).mock.calls[0][0],
),
Buffer.from(
await encryption.decrypt(
(storageService.uploadFile as any).mock.calls[0][0],
),
).toString(),
),
).toEqual(fortuneManifestParams);
});
Expand All @@ -2675,9 +2677,11 @@ describe('JobService', () => {
expect(storageService.uploadFile).toHaveBeenCalled();
expect(
JSON.parse(
await encryption.decrypt(
(storageService.uploadFile as any).mock.calls[0][0],
),
Buffer.from(
await encryption.decrypt(
(storageService.uploadFile as any).mock.calls[0][0],
),
).toString(),
),
).toEqual(fortuneManifestParams);
});
Expand All @@ -2699,9 +2703,11 @@ describe('JobService', () => {
expect(storageService.uploadFile).toHaveBeenCalled();
expect(
JSON.parse(
await encryption.decrypt(
(storageService.uploadFile as any).mock.calls[0][0],
),
Buffer.from(
await encryption.decrypt(
(storageService.uploadFile as any).mock.calls[0][0],
),
).toString(),
),
).toEqual(fortuneManifestParams);
});
Expand Down Expand Up @@ -2768,9 +2774,11 @@ describe('JobService', () => {
expect(storageService.uploadFile).toHaveBeenCalled();
expect(
JSON.parse(
await encryption.decrypt(
(storageService.uploadFile as any).mock.calls[0][0],
),
Buffer.from(
await encryption.decrypt(
(storageService.uploadFile as any).mock.calls[0][0],
),
).toString(),
),
).toEqual(manifest);
});
Expand All @@ -2793,9 +2801,11 @@ describe('JobService', () => {
expect(storageService.uploadFile).toHaveBeenCalled();
expect(
JSON.parse(
await encryption.decrypt(
(storageService.uploadFile as any).mock.calls[0][0],
),
Buffer.from(
await encryption.decrypt(
(storageService.uploadFile as any).mock.calls[0][0],
),
).toString(),
),
).toEqual(manifest);
});
Expand All @@ -2816,9 +2826,11 @@ describe('JobService', () => {
expect(storageService.uploadFile).toHaveBeenCalled();
expect(
JSON.parse(
await encryption.decrypt(
(storageService.uploadFile as any).mock.calls[0][0],
),
Buffer.from(
await encryption.decrypt(
(storageService.uploadFile as any).mock.calls[0][0],
),
).toString(),
),
).toEqual(manifest);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1013,7 +1013,9 @@ export class JobService {

let manifest = await this.storageService.download(jobEntity.manifestUrl);
if (typeof manifest === 'string' && isPGPMessage(manifest)) {
manifest = await this.encryption.decrypt(manifest as any);
manifest = Buffer.from(
await this.encryption.decrypt(manifest),
).toString();
}

if (isValidJSON(manifest)) {
Expand Down Expand Up @@ -1496,7 +1498,9 @@ export class JobService {

let manifest;
if (typeof manifestData === 'string' && isPGPMessage(manifestData)) {
manifestData = await this.encryption.decrypt(manifestData as any);
manifestData = Buffer.from(
await this.encryption.decrypt(manifestData),
).toString();
}

if (isValidJSON(manifestData)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export class StorageService {
typeof fileContent === 'string' &&
EncryptionUtils.isEncrypted(fileContent)
) {
return await this.encryption.decrypt(fileContent);
const decryptedData = await this.encryption.decrypt(fileContent);
return Buffer.from(decryptedData).toString();
} else {
return fileContent;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,12 @@ export class StorageService {
this.pgpConfigService.privateKey!,
this.pgpConfigService.passphrase,
);
const decryptedData = await encryption.decrypt(fileContent);
const content = Buffer.from(decryptedData).toString();
try {
return JSON.parse(await encryption.decrypt(fileContent));
return JSON.parse(content);
} catch {
return await encryption.decrypt(fileContent);
return content;
}
} else {
return fileContent;
Expand Down
59 changes: 59 additions & 0 deletions packages/sdk/typescript/human-protocol-sdk/example/encrypt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Encryption } from '../src/encryption';

const ExampleKeys = {
private: `-----BEGIN PGP PRIVATE KEY BLOCK-----
xVgEZyOGRhYJKwYBBAHaRw8BAQdA6soD3CBjRnPfsYIxOGObykL8X8y+dZlf
IzAI7mk40E4AAQCPRLKy/1n/QxTRk/Ql+Dt2VYADqDmczBxhWELCbz9Wvw/J
zRxleGFtcGxlIDxzaW1wbGVAZXhhbXBsZS5jb20+wowEEBYKAD4FgmcjhkYE
CwkHCAmQZ4KBmVeekE0DFQgKBBYAAgECGQECmwMCHgEWIQQkzuPtNIUkzz4M
CFhngoGZV56QTQAA89oBAKm5Tai1Ynx4BCU6PSLp0QMEE2ImV/LzwHkLMz52
mzeJAP9NyyNyIMNH1SpSezy309UhEdJVapGoXQwO1eQR4B+LCMddBGcjhkYS
CisGAQQBl1UBBQEBB0BykPL7zxjKQpZMYuEnIDBz7vshngm4zJMNOsE6pDSH
NgMBCAcAAP9b+n3/5QKVd0UP/ow3uyH0X44gc2U4fKV8IhZBJLiSEA9ZwngE
GBYKACoFgmcjhkYJkGeCgZlXnpBNApsMFiEEJM7j7TSFJM8+DAhYZ4KBmVee
kE0AAE0WAP9FE0I9dHToxLAkMKiM9tTzL43GVl6K8Lvn9nrLJcfLgQEAtFXL
39GhAUKNbHMpdeEmxukrdF+rXzUfvOsYGPLIgwI=
=GfVY
-----END PGP PRIVATE KEY BLOCK-----`,
public: `-----BEGIN PGP PUBLIC KEY BLOCK-----
xjMEZyOGRhYJKwYBBAHaRw8BAQdA6soD3CBjRnPfsYIxOGObykL8X8y+dZlf
IzAI7mk40E7NHGV4YW1wbGUgPHNpbXBsZUBleGFtcGxlLmNvbT7CjAQQFgoA
PgWCZyOGRgQLCQcICZBngoGZV56QTQMVCAoEFgACAQIZAQKbAwIeARYhBCTO
4+00hSTPPgwIWGeCgZlXnpBNAADz2gEAqblNqLVifHgEJTo9IunRAwQTYiZX
8vPAeQszPnabN4kA/03LI3Igw0fVKlJ7PLfT1SER0lVqkahdDA7V5BHgH4sI
zjgEZyOGRhIKKwYBBAGXVQEFAQEHQHKQ8vvPGMpClkxi4ScgMHPu+yGeCbjM
kw06wTqkNIc2AwEIB8J4BBgWCgAqBYJnI4ZGCZBngoGZV56QTQKbDBYhBCTO
4+00hSTPPgwIWGeCgZlXnpBNAABNFgD/RRNCPXR06MSwJDCojPbU8y+NxlZe
ivC75/Z6yyXHy4EBALRVy9/RoQFCjWxzKXXhJsbpK3Rfq181H7zrGBjyyIMC
=wH1v
-----END PGP PUBLIC KEY BLOCK-----`,
};

const exampleRound = async () => {
const encryption = await Encryption.build(ExampleKeys.private);

const message = Buffer.from(
JSON.stringify(
{
date: new Date().toISOString(),
random: Math.random(),
text: 'Hello from example!',
},
null,
2
)
);

const encrypted = await encryption.signAndEncrypt(message, [
ExampleKeys.public,
]);

const decrypted = await encryption.decrypt(encrypted, ExampleKeys.public);
console.log('Decrypted', JSON.parse(Buffer.from(decrypted).toString()));
};

(async () => {
await exampleRound();
})();
60 changes: 46 additions & 14 deletions packages/sdk/typescript/human-protocol-sdk/src/encryption.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import * as openpgp from 'openpgp';
import { IKeyPair } from './interfaces';

type MessageDataType = string | Uint8Array;

function makeMessageDataBinary(message: MessageDataType): Uint8Array {
if (typeof message === 'string') {
return Buffer.from(message);
}

return message;
}

/**
* ## Introduction
*
Expand Down Expand Up @@ -126,20 +136,21 @@ export class Encryption {
* ```
*/
public async signAndEncrypt(
message: string,
message: MessageDataType,
publicKeys: string[]
): Promise<string> {
const plaintext = message;

const pgpPublicKeys = await Promise.all(
publicKeys.map((armoredKey) => openpgp.readKey({ armoredKey }))
);

const pgpMessage = await openpgp.createMessage({ text: plaintext });
const pgpMessage = await openpgp.createMessage({
binary: makeMessageDataBinary(message),
});
const encrypted = await openpgp.encrypt({
message: pgpMessage,
encryptionKeys: pgpPublicKeys,
signingKeys: this.privateKey,
format: 'armored',
});

return encrypted as string;
Expand Down Expand Up @@ -176,23 +187,43 @@ export class Encryption {
* const resultMessage = await encription.decrypt('message');
* ```
*/
public async decrypt(message: string, publicKey?: string): Promise<string> {
const pgpMessage = await openpgp.readMessage({ armoredMessage: message });
public async decrypt(
message: string,
publicKey?: string
): Promise<Uint8Array> {
const pgpMessage = await openpgp.readMessage({
armoredMessage: message,
});

const decryptionOptions: openpgp.DecryptOptions = {
message: pgpMessage,
decryptionKeys: this.privateKey,
expectSigned: !!publicKey,
format: 'binary',
};

if (publicKey) {
const shouldVerifySignature = !!publicKey;
if (shouldVerifySignature) {
const pgpPublicKey = await openpgp.readKey({ armoredKey: publicKey });
decryptionOptions.verificationKeys = pgpPublicKey;
}

const { data: decrypted } = await openpgp.decrypt(decryptionOptions);
const { data: decrypted, signatures } =
await openpgp.decrypt(decryptionOptions);

/**
* There is an option to automatically verify signatures - `expectSigned`,
* but atm it has a bug - https://github.com/openpgpjs/openpgpjs/issues/1803,
* so we have to verify it manually till it's fixed.
*/
try {
if (shouldVerifySignature) {
await signatures[0].verified;
}
} catch {
throw new Error('Signature could not be verified');
}

return decrypted as string;
return decrypted as Uint8Array;
}

/**
Expand Down Expand Up @@ -419,19 +450,20 @@ export class EncryptionUtils {
* ```
*/
public static async encrypt(
message: string,
message: MessageDataType,
publicKeys: string[]
): Promise<string> {
const plaintext = message;

const pgpPublicKeys = await Promise.all(
publicKeys.map((armoredKey) => openpgp.readKey({ armoredKey }))
);

const pgpMessage = await openpgp.createMessage({ text: plaintext });
const pgpMessage = await openpgp.createMessage({
binary: makeMessageDataBinary(message),
});
const encrypted = await openpgp.encrypt({
message: pgpMessage,
encryptionKeys: pgpPublicKeys,
format: 'armored',
});

return encrypted as string;
Expand Down
Loading