Skip to content

Commit

Permalink
feat: Ethereum Private key (Epk) decryption provider implementation (#…
Browse files Browse the repository at this point in the history
…499)

**Epk-decryption:**
* creation of the package to decrypt ECIES encrypted data with ethereum private keys
  • Loading branch information
vrolland authored Aug 16, 2019
1 parent 813e947 commit 207b762
Show file tree
Hide file tree
Showing 16 changed files with 561 additions and 2 deletions.
24 changes: 24 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,26 @@ jobs:
root: *working_directory
paths:
- packages/epk-signature/coverage/
test-epk-decryption:
docker:
- *node_image
working_directory: *working_directory
steps:
- attach_workspace:
at: *working_directory
- run:
name: 'Build epk-decryption'
command: 'yarn workspace @requestnetwork/epk-decryption run build'
- run:
name: 'Lint epk-decryption'
command: 'yarn workspace @requestnetwork/epk-decryption run lint'
- run:
name: 'Test epk-decryption'
command: 'yarn workspace @requestnetwork/epk-decryption run test'
- persist_to_workspace:
root: *working_directory
paths:
- packages/epk-decryption/coverage/
test-web3-signature:
docker:
- *node_image
Expand Down Expand Up @@ -438,6 +458,9 @@ workflows:
- test-epk-signature:
requires:
- build
- test-epk-decryption:
requires:
- build
- test-web3-signature:
requires:
- build
Expand All @@ -463,5 +486,6 @@ workflows:
- test-advanced-logic
- test-epk-signature
- test-web3-signature
- test-epk-decryption
- test-request-node
- test-utils
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Join the [Request Hub][requesthub-slack-url] to get in touch with us.
| [`@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 |
| [`@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 |
| [`@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 |
| [`@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 |
| [`@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 |
| [`@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 |
| [`@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 |
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"scripts": {
"build": "lerna run build",
"clean": "lerna run clean",
"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",
"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",
"lint": "lerna run lint",
"lerna": "lerna",
"packageJsonLint": "npmPkgJsonLint ./packages",
Expand Down
5 changes: 5 additions & 0 deletions packages/epk-decryption/.huskyrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"hooks": {
"pre-commit": "yarn run lint-staged"
}
}
3 changes: 3 additions & 0 deletions packages/epk-decryption/.lintstagedrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"src/**/*.ts": ["tslint --project . --fix", "prettier --single-quote --write", "git add"]
}
19 changes: 19 additions & 0 deletions packages/epk-decryption/.nycrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"extension": [
".ts"
],
"include": [
"src/*.ts",
"src/**/*.ts"
],
"require": [
"ts-node/register"
],
"reporter": [
"text-summary",
"json",
"html"
],
"sourceMap":true,
"all": true
}
63 changes: 63 additions & 0 deletions packages/epk-decryption/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# @requestnetwork/epk-decryption

Ethereum Private Key Decryption Provider.

`@requestnetwork/epk-decryption` is a typescript library part of the [Request Network protocol](https://github.com/RequestNetwork/requestNetwork).

Implementation of the decryption provider from the private keys.
The decryption provider is used to make decryption in the Request Network Protocol (e.g.: see [Transaction Manager](/packages/transaction-manager)).

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).

## Installation

```bash
npm install @requestnetwork/epk-decryption
```

## Usage

```javascript
import { EncryptionTypes, IdentityTypes } from '@requestnetwork/types'

import EthereumPrivateKeyDecryptionProvider from '@requestnetwork/epk-decryption'

const decryptionParametersExample: EncryptionTypes.IDecryptionParameters = {
key: '0xc87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3',
method: EncryptionTypes.METHOD.ECIES,
};

// Identity from the previous signature parameter
const identityExample: IdentityTypes.IIdentity = {
type: IdentityTypes.TYPE.ETHEREUM_ADDRESS,
value: '0x627306090abab3a6e1400e9345bc60c78a8bef57'
};

// Construct the provider with a
const decryptionProvider = new EthereumPrivateKeyDecryptionProvider(decryptionParametersExample);

// can list the identity usable
const listOfAvailableIdentity = decryptionProvider.getAllRegisteredIdentities(); // [identityExample]

// can decrypt data with identity
const dataToDecrypt = "02....";
const decryptedData = await decryptionProvider.decrypt(dataToDecrypt, identityExample); // "Decrypted data..."

// can add a new decryption parameters
decryptionProvider.addDecryptionParameters({method: EncryptionTypes.METHOD.ECIES, key: ...});

// can remove a decryption parameters from its identity
decryptionProvider.removeRegisteredIdentity({type: IdentityTypes.TYPE.ETHEREUM_ADDRESS, value: ...});

// can remove all decryption parameters
decryptionProvider.clearAllRegisteredIdentities();
```

## Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
[Read the contributing guide](/CONTRIBUTING.md)

## License

[MIT](/LICENSE)
66 changes: 66 additions & 0 deletions packages/epk-decryption/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"name": "@requestnetwork/epk-decryption",
"version": "0.1.0",
"publishConfig": {
"access": "public"
},
"description": "Decryption provider using ethereum private keys.",
"keywords": [
"requestnetwork",
"decryption-provider"
],
"repository": {
"type": "git",
"url": "git+https://github.com/RequestNetwork/requestNetwork.git"
},
"homepage": "https://github.com/RequestNetwork/requestNetwork/tree/master/packages/epk-decryption#readme",
"bugs": {
"url": "https://github.com/RequestNetwork/requestNetwork/issues"
},
"license": "MIT",
"engines": {
"node": ">=8.0.0"
},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"directories": {
"lib": "src",
"test": "test"
},
"files": [
"dist"
],
"scripts": {
"build": "tsc -b",
"clean": "shx rm -rf dist",
"lint": "tslint --project . && eslint \"src/**/*.ts\"",
"lint-staged": "lint-staged",
"test": "nyc mocha --require ts-node/register --require source-map-support/register \"test/**/*.ts\"",
"test:watch": "nyc mocha --watch --watch-extensions ts --require ts-node/register --require source-map-support/register \"test/**/*.ts\""
},
"dependencies": {
"@requestnetwork/types": "0.4.0",
"@requestnetwork/utils": "0.4.0"
},
"devDependencies": {
"@types/chai": "4.1.7",
"@types/mocha": "5.2.6",
"@typescript-eslint/parser": "1.2.0",
"chai": "4.2.0",
"chai-as-promised": "7.1.1",
"eslint": "5.13.0",
"eslint-plugin-spellcheck": "0.0.11",
"eslint-plugin-typescript": "0.14.0",
"husky": "2.4.0",
"lint-staged": "8.1.3",
"mocha": "5.2.0",
"npm-run-all": "4.1.5",
"nyc": "13.2.0",
"prettier": "1.16.4",
"shx": "0.3.2",
"source-map-support": "0.5.10",
"ts-node": "8.0.2",
"tslint": "5.12.1",
"typescript": "3.3.1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { DecryptionProviderTypes, EncryptionTypes, IdentityTypes } from '@requestnetwork/types';

import Utils from '@requestnetwork/utils';

/** Type of the dictionary of decryptionParameters (private keys) indexed by ethereum address */
type IDecryptionParametersDictionary = Map<string, EncryptionTypes.IDecryptionParameters>;

/**
* Implementation of the decryption provider from private key
* Allows to decrypt() with "ethereumAddress" identities thanks to their private key given in constructor() or addDecryptionParameters()
*/
export default class EthereumPrivateKeyDecryptionProvider
implements DecryptionProviderTypes.IDecryptionProvider {
/** list of supported encryption method */
public supportedMethods: EncryptionTypes.METHOD[] = [EncryptionTypes.METHOD.ECIES];
/** list of supported identity types */
public supportedIdentityTypes: IdentityTypes.TYPE[] = [IdentityTypes.TYPE.ETHEREUM_ADDRESS];

/** Dictionary containing all the private keys indexed by address */
private decryptionParametersDictionary: IDecryptionParametersDictionary;

constructor(decryptionParameters?: EncryptionTypes.IDecryptionParameters) {
this.decryptionParametersDictionary = new Map<string, EncryptionTypes.IDecryptionParameters>();
if (decryptionParameters) {
this.addDecryptionParameters(decryptionParameters);
}
}

/**
* Decrypts data
*
* @param data the encrypted data
* @param identity identity to decrypt with
*
* @returns the data decrypted
*/
public async decrypt(data: string, identity: IdentityTypes.IIdentity): Promise<string> {
if (!Utils.multiFormat.isEciesEncryption(data)) {
throw Error(`The data must be encrypted with ${EncryptionTypes.METHOD.ECIES}`);
}

if (!this.supportedIdentityTypes.includes(identity.type)) {
throw Error(`Identity type not supported ${identity.type}`);
}

// toLowerCase to avoid mismatch because of case
const decryptionParameters:
| EncryptionTypes.IDecryptionParameters
| undefined = this.decryptionParametersDictionary.get(identity.value.toLowerCase());

if (!decryptionParameters) {
throw Error(`private key unknown for the identity: ${identity.value}`);
}

return Utils.encryption.decrypt(data, decryptionParameters);
}

/**
* Adds a new private key in the provider
*
* @param decryptionParameters decryption parameters to add
*
* @returns identity from the decryption parameter added
*/
public addDecryptionParameters(
decryptionParameters: EncryptionTypes.IDecryptionParameters,
): IdentityTypes.IIdentity {
if (!this.supportedMethods.includes(decryptionParameters.method)) {
throw Error(`Encryption method not supported ${decryptionParameters.method}`);
}

// compute the address from private key
// toLowerCase to avoid mismatch because of case
const address = Utils.crypto.EcUtils.getAddressFromPrivateKey(
decryptionParameters.key,
).toLowerCase();

this.decryptionParametersDictionary.set(address, decryptionParameters);

return {
type: IdentityTypes.TYPE.ETHEREUM_ADDRESS,
value: address,
};
}

/**
* Removes a private key from the provider
*
* @param identity identity to remove the private key
*
* @returns void
*/
public removeRegisteredIdentity(identity: IdentityTypes.IIdentity): void {
// Check the type of the identity to be sure that the value used to delete will be the right type
if (!this.supportedIdentityTypes.includes(identity.type)) {
throw Error(`Identity type not supported ${identity.type}`);
}

this.decryptionParametersDictionary.delete(identity.value);
}

/**
* Removes all private keys from the provider
*
* @param identity identity to remove the private key
*
* @returns void
*/
public clearAllRegisteredIdentities(): void {
this.decryptionParametersDictionary.clear();
}

/**
* Gets all the identities available to decrypt with
*
* @returns all the identities registered
*/
public getAllRegisteredIdentities(): IdentityTypes.IIdentity[] {
return Array.from(this.decryptionParametersDictionary.keys(), address => ({
type: IdentityTypes.TYPE.ETHEREUM_ADDRESS,
value: address,
}));
}
}
3 changes: 3 additions & 0 deletions packages/epk-decryption/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export {
default as EthereumPrivateKeyDecryptionProvider,
} from './ethereum-private-key-decryption-provider';
Loading

0 comments on commit 207b762

Please sign in to comment.