Skip to content

Commit 207b762

Browse files
authored
feat: Ethereum Private key (Epk) decryption provider implementation (#499)
**Epk-decryption:** * creation of the package to decrypt ECIES encrypted data with ethereum private keys
1 parent 813e947 commit 207b762

16 files changed

+561
-2
lines changed

.circleci/config.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,26 @@ jobs:
275275
root: *working_directory
276276
paths:
277277
- packages/epk-signature/coverage/
278+
test-epk-decryption:
279+
docker:
280+
- *node_image
281+
working_directory: *working_directory
282+
steps:
283+
- attach_workspace:
284+
at: *working_directory
285+
- run:
286+
name: 'Build epk-decryption'
287+
command: 'yarn workspace @requestnetwork/epk-decryption run build'
288+
- run:
289+
name: 'Lint epk-decryption'
290+
command: 'yarn workspace @requestnetwork/epk-decryption run lint'
291+
- run:
292+
name: 'Test epk-decryption'
293+
command: 'yarn workspace @requestnetwork/epk-decryption run test'
294+
- persist_to_workspace:
295+
root: *working_directory
296+
paths:
297+
- packages/epk-decryption/coverage/
278298
test-web3-signature:
279299
docker:
280300
- *node_image
@@ -438,6 +458,9 @@ workflows:
438458
- test-epk-signature:
439459
requires:
440460
- build
461+
- test-epk-decryption:
462+
requires:
463+
- build
441464
- test-web3-signature:
442465
requires:
443466
- build
@@ -463,5 +486,6 @@ workflows:
463486
- test-advanced-logic
464487
- test-epk-signature
465488
- test-web3-signature
489+
- test-epk-decryption
466490
- test-request-node
467491
- test-utils

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Join the [Request Hub][requesthub-slack-url] to get in touch with us.
2727
| [`@requestnetwork/data-format`](/packages/data-format) | [![npm](https://img.shields.io/npm/v/@requestnetwork/data-format.svg)](https://www.npmjs.com/package/@requestnetwork/data-format) | Standards for data stored on Request, like invoices format |
2828
| [`@requestnetwork/epk-signature`](/packages/epk-signature) | [![npm](https://img.shields.io/npm/v/@requestnetwork/epk-signature.svg)](https://www.npmjs.com/package/@requestnetwork/epk-signature) | Sign requests using Ethereum private keys |
2929
| [`@requestnetwork/ethereum-storage`](/packages/ethereum-storage) | [![npm](https://img.shields.io/npm/v/@requestnetwork/ethereum-storage.svg)](https://www.npmjs.com/package/@requestnetwork/ethereum-storage) | Storage of Request data on Ethereum and IPFS |
30+
| [`@requestnetwork/epk-decryption`](/packages/epk-decryption) | [![npm](https://img.shields.io/npm/v/@requestnetwork/epk-decryption.svg)](https://www.npmjs.com/package/@requestnetwork/epk-decryption) | Decrypt encrypted requests using Ethereum private keys |
3031
| [`@requestnetwork/request-logic`](/packages/request-logic) | [![npm](https://img.shields.io/npm/v/@requestnetwork/request-logic.svg)](https://www.npmjs.com/package/@requestnetwork/request-logic) | The Request business logic: properties and actions of requests |
3132
| [`@requestnetwork/request-node`](/packages/request-node) | [![npm](https://img.shields.io/npm/v/@requestnetwork/request-node.svg)](https://www.npmjs.com/package/@requestnetwork/request-node) | Web server that allows easy access to Request system |
3233
| [`@requestnetwork/transaction-manager`](/packages/transaction-manager) | [![npm](https://img.shields.io/npm/v/@requestnetwork/transaction-manager.svg)](https://www.npmjs.com/package/@requestnetwork/transaction-manager) | Creates transactions to be sent to Data Access |

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"scripts": {
1717
"build": "lerna run build",
1818
"clean": "lerna run clean",
19-
"build:tsc": "tsc -b packages/request-client.js packages/data-access packages/integration-test packages/ethereum-storage packages/request-logic packages/request-node packages/types packages/utils packages/types packages/advanced-logic packages/transaction-manager packages/epk-signature packages/data-format",
19+
"build:tsc": "tsc -b packages/request-client.js packages/data-access packages/integration-test packages/ethereum-storage packages/request-logic packages/request-node packages/types packages/utils packages/types packages/advanced-logic packages/transaction-manager packages/epk-signature packages/epk-decryption packages/data-format",
2020
"lint": "lerna run lint",
2121
"lerna": "lerna",
2222
"packageJsonLint": "npmPkgJsonLint ./packages",

packages/epk-decryption/.huskyrc.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"hooks": {
3+
"pre-commit": "yarn run lint-staged"
4+
}
5+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"src/**/*.ts": ["tslint --project . --fix", "prettier --single-quote --write", "git add"]
3+
}

packages/epk-decryption/.nycrc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"extension": [
3+
".ts"
4+
],
5+
"include": [
6+
"src/*.ts",
7+
"src/**/*.ts"
8+
],
9+
"require": [
10+
"ts-node/register"
11+
],
12+
"reporter": [
13+
"text-summary",
14+
"json",
15+
"html"
16+
],
17+
"sourceMap":true,
18+
"all": true
19+
}

packages/epk-decryption/README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# @requestnetwork/epk-decryption
2+
3+
Ethereum Private Key Decryption Provider.
4+
5+
`@requestnetwork/epk-decryption` is a typescript library part of the [Request Network protocol](https://github.com/RequestNetwork/requestNetwork).
6+
7+
Implementation of the decryption provider from the private keys.
8+
The decryption provider is used to make decryption in the Request Network Protocol (e.g.: see [Transaction Manager](/packages/transaction-manager)).
9+
10+
It uses the Request Network Protocol concept of `Identity` described in the [request logic specification](/packages/request-logic/specs/request-logic-specification-v2.0.0.md).
11+
12+
## Installation
13+
14+
```bash
15+
npm install @requestnetwork/epk-decryption
16+
```
17+
18+
## Usage
19+
20+
```javascript
21+
import { EncryptionTypes, IdentityTypes } from '@requestnetwork/types'
22+
23+
import EthereumPrivateKeyDecryptionProvider from '@requestnetwork/epk-decryption'
24+
25+
const decryptionParametersExample: EncryptionTypes.IDecryptionParameters = {
26+
key: '0xc87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3',
27+
method: EncryptionTypes.METHOD.ECIES,
28+
};
29+
30+
// Identity from the previous signature parameter
31+
const identityExample: IdentityTypes.IIdentity = {
32+
type: IdentityTypes.TYPE.ETHEREUM_ADDRESS,
33+
value: '0x627306090abab3a6e1400e9345bc60c78a8bef57'
34+
};
35+
36+
// Construct the provider with a
37+
const decryptionProvider = new EthereumPrivateKeyDecryptionProvider(decryptionParametersExample);
38+
39+
// can list the identity usable
40+
const listOfAvailableIdentity = decryptionProvider.getAllRegisteredIdentities(); // [identityExample]
41+
42+
// can decrypt data with identity
43+
const dataToDecrypt = "02....";
44+
const decryptedData = await decryptionProvider.decrypt(dataToDecrypt, identityExample); // "Decrypted data..."
45+
46+
// can add a new decryption parameters
47+
decryptionProvider.addDecryptionParameters({method: EncryptionTypes.METHOD.ECIES, key: ...});
48+
49+
// can remove a decryption parameters from its identity
50+
decryptionProvider.removeRegisteredIdentity({type: IdentityTypes.TYPE.ETHEREUM_ADDRESS, value: ...});
51+
52+
// can remove all decryption parameters
53+
decryptionProvider.clearAllRegisteredIdentities();
54+
```
55+
56+
## Contributing
57+
58+
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
59+
[Read the contributing guide](/CONTRIBUTING.md)
60+
61+
## License
62+
63+
[MIT](/LICENSE)

packages/epk-decryption/package.json

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
{
2+
"name": "@requestnetwork/epk-decryption",
3+
"version": "0.1.0",
4+
"publishConfig": {
5+
"access": "public"
6+
},
7+
"description": "Decryption provider using ethereum private keys.",
8+
"keywords": [
9+
"requestnetwork",
10+
"decryption-provider"
11+
],
12+
"repository": {
13+
"type": "git",
14+
"url": "git+https://github.com/RequestNetwork/requestNetwork.git"
15+
},
16+
"homepage": "https://github.com/RequestNetwork/requestNetwork/tree/master/packages/epk-decryption#readme",
17+
"bugs": {
18+
"url": "https://github.com/RequestNetwork/requestNetwork/issues"
19+
},
20+
"license": "MIT",
21+
"engines": {
22+
"node": ">=8.0.0"
23+
},
24+
"main": "dist/index.js",
25+
"types": "dist/index.d.ts",
26+
"directories": {
27+
"lib": "src",
28+
"test": "test"
29+
},
30+
"files": [
31+
"dist"
32+
],
33+
"scripts": {
34+
"build": "tsc -b",
35+
"clean": "shx rm -rf dist",
36+
"lint": "tslint --project . && eslint \"src/**/*.ts\"",
37+
"lint-staged": "lint-staged",
38+
"test": "nyc mocha --require ts-node/register --require source-map-support/register \"test/**/*.ts\"",
39+
"test:watch": "nyc mocha --watch --watch-extensions ts --require ts-node/register --require source-map-support/register \"test/**/*.ts\""
40+
},
41+
"dependencies": {
42+
"@requestnetwork/types": "0.4.0",
43+
"@requestnetwork/utils": "0.4.0"
44+
},
45+
"devDependencies": {
46+
"@types/chai": "4.1.7",
47+
"@types/mocha": "5.2.6",
48+
"@typescript-eslint/parser": "1.2.0",
49+
"chai": "4.2.0",
50+
"chai-as-promised": "7.1.1",
51+
"eslint": "5.13.0",
52+
"eslint-plugin-spellcheck": "0.0.11",
53+
"eslint-plugin-typescript": "0.14.0",
54+
"husky": "2.4.0",
55+
"lint-staged": "8.1.3",
56+
"mocha": "5.2.0",
57+
"npm-run-all": "4.1.5",
58+
"nyc": "13.2.0",
59+
"prettier": "1.16.4",
60+
"shx": "0.3.2",
61+
"source-map-support": "0.5.10",
62+
"ts-node": "8.0.2",
63+
"tslint": "5.12.1",
64+
"typescript": "3.3.1"
65+
}
66+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { DecryptionProviderTypes, EncryptionTypes, IdentityTypes } from '@requestnetwork/types';
2+
3+
import Utils from '@requestnetwork/utils';
4+
5+
/** Type of the dictionary of decryptionParameters (private keys) indexed by ethereum address */
6+
type IDecryptionParametersDictionary = Map<string, EncryptionTypes.IDecryptionParameters>;
7+
8+
/**
9+
* Implementation of the decryption provider from private key
10+
* Allows to decrypt() with "ethereumAddress" identities thanks to their private key given in constructor() or addDecryptionParameters()
11+
*/
12+
export default class EthereumPrivateKeyDecryptionProvider
13+
implements DecryptionProviderTypes.IDecryptionProvider {
14+
/** list of supported encryption method */
15+
public supportedMethods: EncryptionTypes.METHOD[] = [EncryptionTypes.METHOD.ECIES];
16+
/** list of supported identity types */
17+
public supportedIdentityTypes: IdentityTypes.TYPE[] = [IdentityTypes.TYPE.ETHEREUM_ADDRESS];
18+
19+
/** Dictionary containing all the private keys indexed by address */
20+
private decryptionParametersDictionary: IDecryptionParametersDictionary;
21+
22+
constructor(decryptionParameters?: EncryptionTypes.IDecryptionParameters) {
23+
this.decryptionParametersDictionary = new Map<string, EncryptionTypes.IDecryptionParameters>();
24+
if (decryptionParameters) {
25+
this.addDecryptionParameters(decryptionParameters);
26+
}
27+
}
28+
29+
/**
30+
* Decrypts data
31+
*
32+
* @param data the encrypted data
33+
* @param identity identity to decrypt with
34+
*
35+
* @returns the data decrypted
36+
*/
37+
public async decrypt(data: string, identity: IdentityTypes.IIdentity): Promise<string> {
38+
if (!Utils.multiFormat.isEciesEncryption(data)) {
39+
throw Error(`The data must be encrypted with ${EncryptionTypes.METHOD.ECIES}`);
40+
}
41+
42+
if (!this.supportedIdentityTypes.includes(identity.type)) {
43+
throw Error(`Identity type not supported ${identity.type}`);
44+
}
45+
46+
// toLowerCase to avoid mismatch because of case
47+
const decryptionParameters:
48+
| EncryptionTypes.IDecryptionParameters
49+
| undefined = this.decryptionParametersDictionary.get(identity.value.toLowerCase());
50+
51+
if (!decryptionParameters) {
52+
throw Error(`private key unknown for the identity: ${identity.value}`);
53+
}
54+
55+
return Utils.encryption.decrypt(data, decryptionParameters);
56+
}
57+
58+
/**
59+
* Adds a new private key in the provider
60+
*
61+
* @param decryptionParameters decryption parameters to add
62+
*
63+
* @returns identity from the decryption parameter added
64+
*/
65+
public addDecryptionParameters(
66+
decryptionParameters: EncryptionTypes.IDecryptionParameters,
67+
): IdentityTypes.IIdentity {
68+
if (!this.supportedMethods.includes(decryptionParameters.method)) {
69+
throw Error(`Encryption method not supported ${decryptionParameters.method}`);
70+
}
71+
72+
// compute the address from private key
73+
// toLowerCase to avoid mismatch because of case
74+
const address = Utils.crypto.EcUtils.getAddressFromPrivateKey(
75+
decryptionParameters.key,
76+
).toLowerCase();
77+
78+
this.decryptionParametersDictionary.set(address, decryptionParameters);
79+
80+
return {
81+
type: IdentityTypes.TYPE.ETHEREUM_ADDRESS,
82+
value: address,
83+
};
84+
}
85+
86+
/**
87+
* Removes a private key from the provider
88+
*
89+
* @param identity identity to remove the private key
90+
*
91+
* @returns void
92+
*/
93+
public removeRegisteredIdentity(identity: IdentityTypes.IIdentity): void {
94+
// Check the type of the identity to be sure that the value used to delete will be the right type
95+
if (!this.supportedIdentityTypes.includes(identity.type)) {
96+
throw Error(`Identity type not supported ${identity.type}`);
97+
}
98+
99+
this.decryptionParametersDictionary.delete(identity.value);
100+
}
101+
102+
/**
103+
* Removes all private keys from the provider
104+
*
105+
* @param identity identity to remove the private key
106+
*
107+
* @returns void
108+
*/
109+
public clearAllRegisteredIdentities(): void {
110+
this.decryptionParametersDictionary.clear();
111+
}
112+
113+
/**
114+
* Gets all the identities available to decrypt with
115+
*
116+
* @returns all the identities registered
117+
*/
118+
public getAllRegisteredIdentities(): IdentityTypes.IIdentity[] {
119+
return Array.from(this.decryptionParametersDictionary.keys(), address => ({
120+
type: IdentityTypes.TYPE.ETHEREUM_ADDRESS,
121+
value: address,
122+
}));
123+
}
124+
}

packages/epk-decryption/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export {
2+
default as EthereumPrivateKeyDecryptionProvider,
3+
} from './ethereum-private-key-decryption-provider';

0 commit comments

Comments
 (0)