-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #35 from lacchain/p256-support
P256 support
- Loading branch information
Showing
18 changed files
with
336 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Changelog | ||
|
||
### 0.0.4 | ||
|
||
* fix ecdsa-p256 signature format to r || s | ||
### 0.0.3 | ||
|
||
### Additions and Improvements | ||
|
||
* Add P256 support for key creation and non-deterministic signing with ECDSA and SHA256 | ||
|
||
### Bug Fixes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,19 @@ | ||
import { DidJwtController } from './did.jwt.controller'; | ||
import { DidCommController } from './didcomm.controller'; | ||
import { Ed25519Controller } from './ed25519.controller'; | ||
import { Secp256k1SignerController } from './secp256k1-signer.controller'; | ||
import { P256Controller } from './p256.controller'; | ||
import { Secp256k1SignerController } from './secp256k1.signer.controller'; | ||
import { Secp256k1Controller } from './secp256k1.controller'; | ||
import { X25519Controller } from './x25519.controller'; | ||
import { P256SignerController } from './p256-signer.controller'; | ||
|
||
export const controllers = [ | ||
Secp256k1Controller, | ||
X25519Controller, | ||
Secp256k1SignerController, | ||
DidJwtController, | ||
DidCommController, | ||
Ed25519Controller | ||
Ed25519Controller, | ||
P256Controller, | ||
P256SignerController | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { | ||
JsonController, | ||
Post, | ||
BadRequestError, | ||
Body | ||
} from 'routing-controllers'; | ||
import { Service } from 'typedi'; | ||
import { ErrorsMessages } from '../constants/errorMessages'; | ||
import { P256PlainMessageDTO } from '@dto/plainMessageDTO'; | ||
import { P256SignerServiceDb } from '@services/p256.signer.service'; | ||
|
||
@JsonController('/p256/sign') | ||
@Service() | ||
export class P256SignerController { | ||
constructor(private readonly p256SignerService: P256SignerServiceDb) {} | ||
|
||
@Post('/plain-message') | ||
async signPlainMessage( | ||
@Body({ validate: true }) message: P256PlainMessageDTO | ||
): Promise<any> { | ||
try { | ||
return this.p256SignerService.signPlainMessage(message); | ||
} catch (error: any) { | ||
throw new BadRequestError( | ||
error.detail ?? error.message ?? ErrorsMessages.INTERNAL_SERVER_ERROR | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { JsonController, Post, BadRequestError } from 'routing-controllers'; | ||
import { Service } from 'typedi'; | ||
import { ErrorsMessages } from '../constants/errorMessages'; | ||
import { P256DbService } from '@services/p256Db.service'; | ||
|
||
@JsonController('/p256') | ||
@Service() | ||
export class P256Controller { | ||
private readonly p256Service: P256DbService; | ||
constructor() { | ||
this.p256Service = new P256DbService(); | ||
} | ||
|
||
@Post('/') | ||
async create(): Promise<any> { | ||
try { | ||
return this.p256Service.createKey(); | ||
} catch (error: any) { | ||
throw new BadRequestError( | ||
error.detail ?? error.message ?? ErrorsMessages.INTERNAL_SERVER_ERROR | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,41 @@ | ||
import { IsOptional, IsString } from 'class-validator'; | ||
|
||
export class PlainMessageDTO { | ||
@IsString() | ||
message!: string; | ||
@IsString() | ||
@IsOptional() | ||
keyId?: string; | ||
} | ||
|
||
export class PlainMessageHashDTO { | ||
@IsString() | ||
messageHash!: string; | ||
@IsString() | ||
@IsOptional() | ||
keyId?: string; | ||
} | ||
|
||
export class Secp256k1PlainMessageDTO extends PlainMessageDTO { | ||
export class Secp256k1PlainMessageDTO extends PlainMessageHashDTO { | ||
@IsString() | ||
address!: string; | ||
} | ||
|
||
export class P256PlainMessageDTO extends PlainMessageDTO { | ||
@IsString() | ||
compressedPublicKey!: string; | ||
@IsOptional() | ||
@IsString() | ||
encoding!: | ||
| 'base64' | ||
| 'base64url' | ||
| 'hex' | ||
| 'binary' | ||
| 'utf8' | ||
| 'utf-8' | ||
| 'utf16le' | ||
| 'latin1' | ||
| 'ascii' | ||
| 'ucs2' | ||
| 'ucs-2'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { | ||
IECDSASignatureMessageResponse, | ||
ISignPlainMessageByCompressedPublicKey | ||
} from 'src/interfaces/signer/signer.interface'; | ||
|
||
export interface ECDSASignerService { | ||
/** | ||
* | ||
* @param message - The 'hashed' message to be signed - MUST start with '0x' | ||
*/ | ||
signPlainMessage( | ||
message: ISignPlainMessageByCompressedPublicKey | ||
): Promise<IECDSASignatureMessageResponse>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,15 @@ | ||
import { | ||
ISignPlainMessageByAddress, | ||
ISecp256k1SignatureMessageResponse | ||
IECDSASignatureMessageResponse | ||
} from 'src/interfaces/signer/signer.interface'; | ||
|
||
export interface Secp256k1GenericSignerService { | ||
/** | ||
* | ||
* @param message - The 'hashed' message to be signed - MUST start with '0x' | ||
* @param {ISignPlainMessageByAddress} message - | ||
* The 'hashed' message to be signed - MUST start with '0x' | ||
*/ | ||
signPlainMessage( | ||
message: ISignPlainMessageByAddress | ||
): Promise<ISecp256k1SignatureMessageResponse>; | ||
): Promise<IECDSASignatureMessageResponse>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import { log4TSProvider } from '../config'; | ||
import { Service } from 'typedi'; | ||
import { | ||
IECDSASignatureMessageResponse, | ||
ISignPlainMessageByCompressedPublicKey | ||
} from 'src/interfaces/signer/signer.interface'; | ||
import { ECDSASignerService } from './interfaces/ecdsa.signer'; | ||
import { P256DbService } from './p256Db.service'; | ||
import { createSign, KeyObject, webcrypto } from 'node:crypto'; | ||
import { BadRequestError, InternalServerError } from 'routing-controllers'; | ||
import { ErrorsMessages } from '../constants/errorMessages'; | ||
import { isHexString } from 'ethers'; | ||
|
||
@Service() | ||
// eslint-disable-next-line max-len | ||
export class P256SignerServiceDb implements ECDSASignerService { | ||
protected readonly p256DbService = new P256DbService(); | ||
log = log4TSProvider.getLogger('p256-plain-message-signer'); | ||
/** | ||
* @reference https://nodejs.org/docs/latest-v16.x/api/crypto.html#class-sign ... | ||
* If encoding is not provided in {@link ISignPlainMessageByCompressedPublicKey} | ||
* request, and the data is a string, an encoding of 'utf8' | ||
* is enforced. If data is a Buffer, TypedArray, orDataView, | ||
* then inputEncoding is ignored. | ||
* @param {ISignPlainMessageByCompressedPublicKey} request - message request to sign. | ||
* @return {Promise<IECDSASignatureMessageResponse>} | ||
*/ | ||
async signPlainMessage( | ||
request: ISignPlainMessageByCompressedPublicKey | ||
): Promise<IECDSASignatureMessageResponse> { | ||
const publicKey = request.compressedPublicKey; | ||
const foundKey = await this.p256DbService.getKeyByCompressedPublicKey( | ||
publicKey | ||
); | ||
|
||
if (!(foundKey.x && foundKey.y)) { | ||
throw new InternalServerError(ErrorsMessages.INTERNAL_SERVER_ERROR); | ||
} | ||
|
||
const jwk = { | ||
crv: 'P-256', | ||
kty: 'EC', | ||
x: Buffer.from(foundKey.x.replace('0x', ''), 'hex').toString('base64url'), | ||
y: Buffer.from(foundKey.y.replace('0x', ''), 'hex').toString('base64url'), | ||
d: Buffer.from(foundKey.key.replace('0x', ''), 'hex').toString( | ||
'base64url' | ||
) | ||
}; | ||
|
||
const importedKey = await webcrypto.subtle.importKey( | ||
'jwk', | ||
jwk, | ||
{ name: 'ECDSA', namedCurve: 'P-256' }, | ||
true, | ||
['sign'] | ||
); | ||
|
||
let message = request.message; | ||
const sign = createSign('SHA256'); | ||
if (request.encoding && request.encoding === 'hex') { | ||
message = message.replace('0x', ''); | ||
if (!isHexString(message.startsWith('0x') ? message : '0x' + message)) { | ||
throw new BadRequestError(ErrorsMessages.INVALID_HEX_MESSAGE_ERROR); | ||
} | ||
} | ||
sign.update(message, request.encoding ? request.encoding : 'utf8'); | ||
sign.end(); | ||
const sig = | ||
'0x' + | ||
sign.sign( | ||
{ key: KeyObject.from(importedKey), dsaEncoding: 'ieee-p1363' }, | ||
'hex' | ||
); | ||
const signature = { | ||
signature: sig | ||
}; | ||
return signature; | ||
} | ||
} |
Oops, something went wrong.