diff --git a/packages/auto-id/package.json b/packages/auto-id/package.json index 558810bc..c3a70e4c 100644 --- a/packages/auto-id/package.json +++ b/packages/auto-id/package.json @@ -10,7 +10,9 @@ }, "dependencies": { "@autonomys/auto-utils": "workspace:*", - "@types/node": "^20.12.12" + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/asn1-x509": "^2.3.8", + "asn1js": "^3.0.5" }, "files": [ "dist", @@ -18,6 +20,7 @@ ], "devDependencies": { "@types/jest": "^29.5.12", + "@types/node": "^20.12.12", "jest": "^29.7.0", "ts-jest": "^29.1.4", "ts-node": "^10.9.2", diff --git a/packages/auto-id/src/index.ts b/packages/auto-id/src/index.ts index 310afd44..55276676 100644 --- a/packages/auto-id/src/index.ts +++ b/packages/auto-id/src/index.ts @@ -1 +1,2 @@ export * from './keyManagement' +export * from './utils' diff --git a/packages/auto-id/src/utils.ts b/packages/auto-id/src/utils.ts new file mode 100644 index 00000000..62093fe2 --- /dev/null +++ b/packages/auto-id/src/utils.ts @@ -0,0 +1,23 @@ +import { ObjectIdentifier } from 'asn1js' + +/** + * Encodes a given string representation of an OID into its DER format. + * This function is specifically used to encode signature algorithm OIDs. + * + * @param oid The string representation of the ObjectIdentifier to be encoded. + * @returns Uint8Array containing the DER encoded OID along with NULL params of X.509 signature algorithm. + */ +export function derEncodeSignatureAlgorithmOID(oid: string): Uint8Array { + const objectIdentifier = new ObjectIdentifier({ value: oid }) + const berArrayBuffer = objectIdentifier.toBER(false) + + // Typically, in X.509, the algorithm identifier is followed by parameters; for many algorithms, this is just NULL. + const nullParameter = [0x05, 0x00] // DER encoding for NULL + + // Calculate the total length including OID and NULL parameter + const totalLength = berArrayBuffer.byteLength + nullParameter.length + + const sequenceHeader = [0x30, totalLength] // 0x30 is the DER tag for SEQUENCE + + return new Uint8Array([...sequenceHeader, ...new Uint8Array(berArrayBuffer), ...nullParameter]) +} diff --git a/packages/auto-id/tests/issuer.cert.der b/packages/auto-id/tests/issuer.cert.der new file mode 100644 index 00000000..c10a4217 Binary files /dev/null and b/packages/auto-id/tests/issuer.cert.der differ diff --git a/packages/auto-id/tests/utils.test.ts b/packages/auto-id/tests/utils.test.ts new file mode 100644 index 00000000..1b58b8dc --- /dev/null +++ b/packages/auto-id/tests/utils.test.ts @@ -0,0 +1,30 @@ +import { AsnParser } from '@peculiar/asn1-schema' // A library to parse ASN.1 +// TODO: See why X509Certificate (from crypto) is not compatible argument. +import { Certificate } from '@peculiar/asn1-x509' // Assuming X.509 certificate handling +import fs from 'fs' +import { derEncodeSignatureAlgorithmOID } from '../src/utils' + +describe('Verify crypto functions', () => { + test('DER encode signature algorithm OID from a certificate', () => { + // Load the certificate from a file + const certPath = 'tests/issuer.cert.der' + const certData = fs.readFileSync(certPath) + + // Load and parse the certificate + const cert = AsnParser.parse(certData, Certificate) + + // Extract the OID of the signature algorithm + const signatureAlgorithmOID = cert.signatureAlgorithm.algorithm + + // DER encode the OID + const derEncodedOID = derEncodeSignatureAlgorithmOID(signatureAlgorithmOID) + // + // console.log(Buffer.from(derEncodedOID)) + + // Convert derEncodedOID to hex string for comparison + const derEncodedOIDHex = Buffer.from(derEncodedOID).toString('hex') + + // Expected DER encoded OID from the result of tests in https://github.com/subspace/subspace/blob/d875a5aac35c1732eec61ce4359782eff58ff6fc/domains/pallets/auto-id/src/tests.rs#L127 + expect(derEncodedOIDHex).toEqual('300d06092a864886f70d01010b0500') + }) +}) diff --git a/packages/auto-utils/__test__/crypto.test.ts b/packages/auto-utils/__test__/crypto.test.ts new file mode 100644 index 00000000..636aa132 --- /dev/null +++ b/packages/auto-utils/__test__/crypto.test.ts @@ -0,0 +1,16 @@ +import { blake2b_256, stringToUint8Array } from '../src/crypto' + +describe('Verify crypto functions', () => { + test('Check blake2b_256 return the hash of the data', async () => { + const message = 'Hello, world!' + const message_bytes = stringToUint8Array(message) + const hash = blake2b_256(message_bytes) + expect(hash).toEqual('0xb5da441cfe72ae042ef4d2b17742907f675de4da57462d4c3609c2e2ed755970') + }) + + test('Check stringToUint8Array return the byte array of the string', async () => { + const message = 'Hello, world!' + const byteArray = stringToUint8Array(message) + expect(byteArray).toBeInstanceOf(Uint8Array) + }) +}) diff --git a/packages/auto-utils/src/crypto.ts b/packages/auto-utils/src/crypto.ts new file mode 100644 index 00000000..1dce5c74 --- /dev/null +++ b/packages/auto-utils/src/crypto.ts @@ -0,0 +1,31 @@ +import { blake2AsHex } from '@polkadot/util-crypto' + +/** + * Hashes the given data using BLAKE2b-256. + * + * @param data Uint8Array - The data to be hashed. + * @returns string - The BLAKE2b-256 hash of the data as a hex string. + */ +export function blake2b_256(data: Uint8Array): string { + return blake2AsHex(data, 256) +} + +/** + * Converts a string to a Uint8Array using UTF-8 encoding. + * + * This function uses the TextEncoder API to convert a plain string into its equivalent byte array + * representation in UTF-8 format. It is useful for scenarios where string data needs to be processed + * in a binary format, such as hashing or cryptographic operations. + * + * @param text The string to be converted into a byte array. + * @returns Uint8Array - The UTF-8 encoded byte array representation of the input string. + * + * @example + * const text = "Hello, world!"; + * const byteArray = stringToUint8Array(text); + * console.log(byteArray); // Outputs the byte array of the string + */ +export function stringToUint8Array(text: string): Uint8Array { + const encoder = new TextEncoder() // Create a new TextEncoder instance + return encoder.encode(text) // Encode the string to a Uint8Array using UTF-8 encoding +} diff --git a/packages/auto-utils/src/index.ts b/packages/auto-utils/src/index.ts index d38eecfc..520949a3 100644 --- a/packages/auto-utils/src/index.ts +++ b/packages/auto-utils/src/index.ts @@ -1,4 +1,5 @@ export * from './api' +export * from './crypto' export * from './network' export * from './read' export * from './save' diff --git a/yarn.lock b/yarn.lock index 85701739..b8296033 100644 --- a/yarn.lock +++ b/yarn.lock @@ -32,8 +32,11 @@ __metadata: resolution: "@autonomys/auto-id@workspace:packages/auto-id" dependencies: "@autonomys/auto-utils": "workspace:*" + "@peculiar/asn1-schema": "npm:^2.3.8" + "@peculiar/asn1-x509": "npm:^2.3.8" "@types/jest": "npm:^29.5.12" "@types/node": "npm:^20.12.12" + asn1-ts: "npm:^8.0.2" jest: "npm:^29.7.0" ts-jest: "npm:^29.1.4" ts-node: "npm:^10.9.2" @@ -914,6 +917,30 @@ __metadata: languageName: node linkType: hard +"@peculiar/asn1-schema@npm:^2.3.8": + version: 2.3.8 + resolution: "@peculiar/asn1-schema@npm:2.3.8" + dependencies: + asn1js: "npm:^3.0.5" + pvtsutils: "npm:^1.3.5" + tslib: "npm:^2.6.2" + checksum: 10c0/65f16b2a7eb91365b6dac47730ffcad4617ef04b821e0a4286c379ac7283588b0a6744032ee686e0914a0886c2a055108ed945b9c4d22821a3b123640b61f3b2 + languageName: node + linkType: hard + +"@peculiar/asn1-x509@npm:^2.3.8": + version: 2.3.8 + resolution: "@peculiar/asn1-x509@npm:2.3.8" + dependencies: + "@peculiar/asn1-schema": "npm:^2.3.8" + asn1js: "npm:^3.0.5" + ipaddr.js: "npm:^2.1.0" + pvtsutils: "npm:^1.3.5" + tslib: "npm:^2.6.2" + checksum: 10c0/75d217e679cb0baa4d3e68eed0a7981f5eed1d5fe1812852987a29bab293995b694d15b3784b06fbd688162a7098915dc8fbbd167331eaaedb3f4951620af727 + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -1798,6 +1825,26 @@ __metadata: languageName: node linkType: hard +"asn1-ts@npm:^8.0.2": + version: 8.0.2 + resolution: "asn1-ts@npm:8.0.2" + dependencies: + tslib: "npm:^2.4.1" + checksum: 10c0/37ca66c319730ae7a2762642a3bb867b298a1ad721a11f859f900332b39117497fd337ba16e7d4c4f7dc9bd6f5e577d8d49c07edcc7fdebeff1d42d7a66a3112 + languageName: node + linkType: hard + +"asn1js@npm:^3.0.5": + version: 3.0.5 + resolution: "asn1js@npm:3.0.5" + dependencies: + pvtsutils: "npm:^1.3.2" + pvutils: "npm:^1.1.3" + tslib: "npm:^2.4.0" + checksum: 10c0/bb8eaf4040c8f49dd475566874986f5976b81bae65a6b5526e2208a13cdca323e69ce297bcd435fdda3eb6933defe888e71974d705b6fcb14f2734a907f8aed4 + languageName: node + linkType: hard + "babel-jest@npm:^29.7.0": version: 29.7.0 resolution: "babel-jest@npm:29.7.0" @@ -2937,6 +2984,13 @@ __metadata: languageName: node linkType: hard +"ipaddr.js@npm:^2.1.0": + version: 2.2.0 + resolution: "ipaddr.js@npm:2.2.0" + checksum: 10c0/e4ee875dc1bd92ac9d27e06cfd87cdb63ca786ff9fd7718f1d4f7a8ef27db6e5d516128f52d2c560408cbb75796ac2f83ead669e73507c86282d45f84c5abbb6 + languageName: node + linkType: hard + "is-arrayish@npm:^0.2.1": version: 0.2.1 resolution: "is-arrayish@npm:0.2.1" @@ -4273,6 +4327,22 @@ __metadata: languageName: node linkType: hard +"pvtsutils@npm:^1.3.2, pvtsutils@npm:^1.3.5": + version: 1.3.5 + resolution: "pvtsutils@npm:1.3.5" + dependencies: + tslib: "npm:^2.6.1" + checksum: 10c0/d425aed316907e0b447a459bfb97c55d22270c3cfdba5a07ec90da0737b0e40f4f1771a444636f85bb6a453de90ff8c6b5f4f6ddba7597977166af49974b4534 + languageName: node + linkType: hard + +"pvutils@npm:^1.1.3": + version: 1.1.3 + resolution: "pvutils@npm:1.1.3" + checksum: 10c0/23489e6b3c76b6afb6964a20f891d6bef092939f401c78bba186b2bfcdc7a13904a0af0a78f7933346510f8c1228d5ab02d3c80e968fd84d3c76ff98d8ec9aac + languageName: node + linkType: hard + "queue-microtask@npm:^1.2.2": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" @@ -4796,6 +4866,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^2.4.0, tslib@npm:^2.4.1, tslib@npm:^2.6.1": + version: 2.6.3 + resolution: "tslib@npm:2.6.3" + checksum: 10c0/2598aef53d9dbe711af75522464b2104724d6467b26a60f2bdac8297d2b5f1f6b86a71f61717384aa8fd897240467aaa7bcc36a0700a0faf751293d1331db39a + languageName: node + linkType: hard + "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0"