mirror of
https://github.com/mosip/inji-wallet.git
synced 2026-01-09 13:38:01 -05:00
[INJIMOB-3015] add noble ecr1 signature and remove jose signing for ios (#1930)
Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com> Co-authored-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>
This commit is contained in:
@@ -108,11 +108,8 @@ export const openID4VPServices = () => {
|
||||
const key = await fetchKeyPair(mdocAuthenticationAlgorithm);
|
||||
const signature = await createSignature(
|
||||
key.privateKey,
|
||||
'',
|
||||
payload,
|
||||
mdocAuthenticationAlgorithm,
|
||||
'',
|
||||
payload,
|
||||
);
|
||||
|
||||
if (signature) {
|
||||
|
||||
36
package-lock.json
generated
36
package-lock.json
generated
@@ -18,6 +18,7 @@
|
||||
"@expo/metro-config": "~0.18.11",
|
||||
"@invertase/react-native-apple-authentication": "^2.3.0",
|
||||
"@iriscan/biometric-sdk-react-native": "0.2.6",
|
||||
"@noble/curves": "^1.9.0",
|
||||
"@noble/ed25519": "^2.1.0",
|
||||
"@noble/hashes": "^1.5.0",
|
||||
"@noble/secp256k1": "2.0.0",
|
||||
@@ -6069,6 +6070,21 @@
|
||||
"eslint-scope": "5.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/curves": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.0.tgz",
|
||||
"integrity": "sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.21.3 || >=16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/ed25519": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-2.1.0.tgz",
|
||||
@@ -6079,9 +6095,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz",
|
||||
"integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==",
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
|
||||
"integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^14.21.3 || >=16"
|
||||
@@ -34899,15 +34915,23 @@
|
||||
"eslint-scope": "5.1.1"
|
||||
}
|
||||
},
|
||||
"@noble/curves": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.0.tgz",
|
||||
"integrity": "sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg==",
|
||||
"requires": {
|
||||
"@noble/hashes": "1.8.0"
|
||||
}
|
||||
},
|
||||
"@noble/ed25519": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-2.1.0.tgz",
|
||||
"integrity": "sha512-KM4qTyXPinyCgMzeYJH/UudpdL+paJXtY3CHtHYZQtBkS8MZoPr4rOikZllIutJe0d06QDQKisyn02gxZ8TcQA=="
|
||||
},
|
||||
"@noble/hashes": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz",
|
||||
"integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA=="
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
|
||||
"integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="
|
||||
},
|
||||
"@noble/secp256k1": {
|
||||
"version": "2.0.0",
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"@expo/metro-config": "~0.18.11",
|
||||
"@invertase/react-native-apple-authentication": "^2.3.0",
|
||||
"@iriscan/biometric-sdk-react-native": "0.2.6",
|
||||
"@noble/curves": "^1.9.0",
|
||||
"@noble/ed25519": "^2.1.0",
|
||||
"@noble/hashes": "^1.5.0",
|
||||
"@noble/secp256k1": "2.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'react-native-get-random-values';
|
||||
import {RSA} from 'react-native-rsa-native';
|
||||
import forge from 'node-forge';
|
||||
import jose from 'node-jose';
|
||||
import {
|
||||
BIOMETRIC_CANCELLED,
|
||||
DEBUG_MODE_ENABLED,
|
||||
@@ -16,8 +16,8 @@ import base64url from 'base64url';
|
||||
import {hmac} from '@noble/hashes/hmac';
|
||||
import {sha256} from '@noble/hashes/sha256';
|
||||
import {sha512} from '@noble/hashes/sha512';
|
||||
import 'react-native-get-random-values';
|
||||
import * as secp from '@noble/secp256k1';
|
||||
import {p256} from '@noble/curves/p256';
|
||||
import * as ed from '@noble/ed25519';
|
||||
import base64 from 'react-native-base64';
|
||||
import {KeyTypes} from './KeyTypes';
|
||||
@@ -89,13 +89,11 @@ export async function generateKeyPairECR1() {
|
||||
privateKey: '',
|
||||
};
|
||||
}
|
||||
const keystore = jose.JWK.createKeyStore();
|
||||
const key = await keystore.generate('EC', 'P-256');
|
||||
const jwkPublicKey = key.toJSON(); // Public key JWK
|
||||
const jwkPrivateKey = key.toJSON(true); // Private key JWK (include private part)
|
||||
const privKey = p256.utils.randomPrivateKey();
|
||||
const pubKey = p256.getPublicKey(privKey, false);
|
||||
return {
|
||||
publicKey: JSON.stringify(jwkPublicKey),
|
||||
privateKey: JSON.stringify(jwkPrivateKey),
|
||||
publicKey: Buffer.from(pubKey).toString('base64'),
|
||||
privateKey: Buffer.from(privKey).toString('base64'),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -192,11 +190,8 @@ export async function getJWT(
|
||||
const preHash = header64 + '.' + payLoad64;
|
||||
const signature64 = await createSignature(
|
||||
privateKey,
|
||||
alias,
|
||||
preHash,
|
||||
keyType,
|
||||
header,
|
||||
payLoad,
|
||||
);
|
||||
return header64 + '.' + payLoad64 + '.' + signature64;
|
||||
} catch (error) {
|
||||
@@ -208,29 +203,22 @@ export async function getJWT(
|
||||
}
|
||||
}
|
||||
|
||||
export async function createSignature(
|
||||
privateKey,
|
||||
alias,
|
||||
preHash,
|
||||
keyType: string,
|
||||
header,
|
||||
payload,
|
||||
) {
|
||||
export async function createSignature(privateKey, payload, keyType: string) {
|
||||
switch (keyType) {
|
||||
case KeyTypes.RS256:
|
||||
return createSignatureRSA(privateKey, preHash);
|
||||
return createSignatureRSA(privateKey, payload);
|
||||
case KeyTypes.ES256:
|
||||
return createSignatureECR1(privateKey, header, payload, preHash);
|
||||
return createSignatureECR1(privateKey, payload);
|
||||
case KeyTypes.ES256K:
|
||||
return createSignatureECK1(privateKey, preHash);
|
||||
return createSignatureECK1(privateKey, payload);
|
||||
case KeyTypes.ED25519:
|
||||
return createSignatureED(privateKey, preHash);
|
||||
return createSignatureED(privateKey, payload);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export async function createSignatureRSA(privateKey: string, preHash: string) {
|
||||
export async function createSignatureRSA(privateKey: string, payload: string) {
|
||||
let signature64;
|
||||
|
||||
if (!isHardwareKeystoreExists) {
|
||||
@@ -240,12 +228,12 @@ export async function createSignatureRSA(privateKey: string, preHash: string) {
|
||||
signature64 = await RNSecureKeystoreModule.sign(
|
||||
KeyTypes.RS256,
|
||||
KeyTypes.RS256,
|
||||
preHash,
|
||||
payload,
|
||||
);
|
||||
else {
|
||||
const key = forge.pki.privateKeyFromPem(privateKey);
|
||||
const md = forge.md.sha256.create();
|
||||
md.update(preHash, 'utf8');
|
||||
md.update(payload, 'utf8');
|
||||
|
||||
const signature = key.sign(md);
|
||||
signature64 = encodeB64(signature);
|
||||
@@ -254,24 +242,19 @@ export async function createSignatureRSA(privateKey: string, preHash: string) {
|
||||
return replaceCharactersInB64(signature64);
|
||||
}
|
||||
|
||||
export async function createSignatureECK1(privateKey, prehash) {
|
||||
const sha = sha256(prehash);
|
||||
export async function createSignatureECK1(privateKey, payload) {
|
||||
const sha = sha256(payload);
|
||||
const sign = await secp.signAsync(sha, privateKey, {lowS: false});
|
||||
return base64url(Buffer.from(sign.toCompactRawBytes()));
|
||||
}
|
||||
|
||||
export async function createSignatureED(privateKey, prehash) {
|
||||
const messageBytes = new TextEncoder().encode(prehash);
|
||||
export async function createSignatureED(privateKey, payload) {
|
||||
const messageBytes = new TextEncoder().encode(payload);
|
||||
const privateKeyUint8 = Uint8Array.from(privateKey);
|
||||
const sign = await ed.signAsync(messageBytes, privateKeyUint8);
|
||||
return replaceCharactersInB64(Buffer.from(sign).toString('base64'));
|
||||
}
|
||||
export async function createSignatureECR1(
|
||||
privateKey,
|
||||
header,
|
||||
payload,
|
||||
preHash,
|
||||
) {
|
||||
export async function createSignatureECR1(privateKey, payload) {
|
||||
if (!isHardwareKeystoreExists) {
|
||||
throw Error;
|
||||
} else {
|
||||
@@ -279,7 +262,7 @@ export async function createSignatureECR1(
|
||||
let signature64 = await RNSecureKeystoreModule.sign(
|
||||
KeyTypes.ES256,
|
||||
KeyTypes.ES256,
|
||||
preHash,
|
||||
payload,
|
||||
);
|
||||
const base64DeodedSignature = base64.decode(
|
||||
signature64.replace(/\n/g, ''),
|
||||
@@ -291,19 +274,12 @@ export async function createSignatureECR1(
|
||||
return replaceCharactersInB64(signature64);
|
||||
}
|
||||
}
|
||||
const sha = sha256(payload);
|
||||
|
||||
const key = await jose.JWK.asKey(JSON.parse(privateKey));
|
||||
|
||||
const signer = await jose.JWS.createSign(
|
||||
{format: 'compact', fields: header},
|
||||
{key, reference: false},
|
||||
);
|
||||
const jws = await signer.update(JSON.stringify(payload), 'base64').final();
|
||||
const jwsParts = jws.split('.');
|
||||
if (jwsParts.length !== 3) {
|
||||
throw new Error('Invalid JWS format');
|
||||
}
|
||||
return jwsParts[2];
|
||||
const sign = await p256.sign(sha, Buffer.from(privateKey, 'base64'), {
|
||||
lowS: false,
|
||||
});
|
||||
return base64url(Buffer.from(sign.toCompactRawBytes()));
|
||||
}
|
||||
|
||||
export function replaceCharactersInB64(encodedB64: string) {
|
||||
@@ -438,8 +414,12 @@ export async function fetchKeyPair(keyType: any) {
|
||||
const keyPair = await RNSecureKeystoreModule.retrieveGenericKey(
|
||||
keyType,
|
||||
);
|
||||
const publicKey = keyPair[1];
|
||||
const privateKey = keyPair[0];
|
||||
let publicKey = keyPair[1];
|
||||
let privateKey = keyPair[0];
|
||||
if (keyType == KeyTypes.ES256) {
|
||||
publicKey = Buffer.from(publicKey, 'base64');
|
||||
privateKey = Buffer.from(privateKey, 'base64');
|
||||
}
|
||||
return {
|
||||
publicKey: publicKey,
|
||||
privateKey: privateKey,
|
||||
|
||||
@@ -329,9 +329,15 @@ async function getJWKRSA(publicKey): Promise<any> {
|
||||
return publicKeyJWKString.toJSON();
|
||||
}
|
||||
async function getJWKECR1(publicKey): Promise<any> {
|
||||
if (isIOS()) return JSON.parse(publicKey);
|
||||
const publicKeyJWKString = await jose.JWK.asKey(publicKey, 'pem');
|
||||
return publicKeyJWKString.toJSON();
|
||||
const x = base64url(Buffer.from(publicKey.slice(1, 33))); // Skip the first byte (0x04) in the uncompressed public key
|
||||
const y = base64url(Buffer.from(publicKey.slice(33,65)));
|
||||
const jwk = {
|
||||
kty: 'EC',
|
||||
crv: 'P-256',
|
||||
x: x,
|
||||
y: y,
|
||||
};
|
||||
return jwk;
|
||||
}
|
||||
function getJWKECK1(publicKey): any {
|
||||
const x = base64url(Buffer.from(publicKey.slice(1, 33))); // Skip the first byte (0x04) in the uncompressed public key
|
||||
|
||||
Reference in New Issue
Block a user