Skip to content

Commit

Permalink
refactor!: remove asymmetric crypto utils
Browse files Browse the repository at this point in the history
  • Loading branch information
arty-name committed Aug 17, 2023
1 parent ac7d656 commit d7c53aa
Show file tree
Hide file tree
Showing 10 changed files with 40 additions and 199 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"set:version": "npm version --no-git-tag-version --no-workspaces-update --workspaces --include-workspace-root",
"style": "prettier -l packages",
"style:fix": "yarn style --write",
"test": "jest --coverage --selectProjects=unit",
"test": "env LANG=C jest --coverage --selectProjects=unit",
"test:breaking": "jest --selectProjects=breaking",
"test:ci": "yarn test --ci --forceExit",
"test:integration": "jest -c tests/integration/jest.config.integration.js",
Expand Down
39 changes: 24 additions & 15 deletions packages/did/src/DidDetails/LightDidDetails.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
* found in the LICENSE file in the root directory of this source tree.
*/

import { DidDocument, DidServiceEndpoint, DidUri } from '@kiltprotocol/types'
import {
DidDocument,
DidServiceEndpoint,
DidUri,
KiltEncryptionKeypair,
} from '@kiltprotocol/types'
import { Crypto } from '@kiltprotocol/utils'

import * as Did from '../index.js'
Expand All @@ -20,12 +25,20 @@ import * as Did from '../index.js'
* - authorizeExtrinsic
*/

function makeEncryptionKeypair(): KiltEncryptionKeypair {
const publicKey = Crypto.hash('public', 256)
const secretKey = Crypto.hash('secret', 256)
return {
secretKey,
publicKey,
type: 'x25519',
}
}

describe('When creating an instance from the details', () => {
it('correctly assign the right sr25519 authentication key, x25519 encryption key, and service endpoints', () => {
const authKey = Crypto.makeKeypairFromSeed(undefined, 'sr25519')
const encKey = Crypto.makeEncryptionKeypairFromSeed(
new Uint8Array(32).fill(1)
)
const encKey = makeEncryptionKeypair()
const service: DidServiceEndpoint[] = [
{
id: '#service-1',
Expand All @@ -46,7 +59,7 @@ describe('When creating an instance from the details', () => {
})

expect(lightDid).toEqual(<DidDocument>{
uri: `did:kilt:light:00${authKey.address}:z17GNCdxLqMYTMC5pnnDrPZGxLEFcXvDamtGNXeNkfSaFf8cktX6erFJiQy8S3ugL981NNys7Rz8DJiaNPZi98v1oeFVL7PjUGNTz1g3jgZo4VgQri2SYHBifZFX9foHZH4DreZXFN66k5dPrvAtBpFXaiG2WZkkxsnxNWxYpqWPPcxvbTE6pJbXxWKjRUd7rog1h9vjA93QA9jMDxm6BSGJHACFgSPUU3UTLk2kjNwT2bjZVvihVFu1zibxwHjowb7N6UQfieJ7ny9HnaQy64qJvGqh4NNtpwkhwm5DTYUoAeAhjt3a6TWyxmBgbFdZF7`,
uri: `did:kilt:light:00${authKey.address}:z17GNCdxLqak5QojTgsFXFzCtSPh9ihEZKDYxcgUb5yjRAz1VtgWiDrRhVLwjgV6cKdPgPpEMFwCfpjjS88gh34Y4Yb7M6aQA1rk62hL15BKtiAdJYieDEaEsYu1Uj7tDUVXFPyEq6j9tKA6xNpT92uYbvveaD9egUdY2htCQN6cL9xvdbCS4Ywrx1vz38NqY1ke3o59zVUw6jahvppwdtqhGiowQhKcHC3d7n2eNtW2rcZ2VmWk63AXkGzmaQUrkkPTqq6erZRXmwk3rmb7tsDuziC44RH22Lbyv9Zp6DddZykmWnHVP7SprWAxmSpQZF`,
authentication: [
{
id: '#authentication',
Expand Down Expand Up @@ -78,9 +91,7 @@ describe('When creating an instance from the details', () => {

it('correctly assign the right ed25519 authentication key and encryption key', () => {
const authKey = Crypto.makeKeypairFromSeed()
const encKey = Crypto.makeEncryptionKeypairFromSeed(
new Uint8Array(32).fill(1)
)
const encKey = makeEncryptionKeypair()

const lightDid = Did.createLightDidDocument({
authentication: [authKey],
Expand All @@ -90,7 +101,7 @@ describe('When creating an instance from the details', () => {
expect(Did.parse(lightDid.uri).address).toStrictEqual(authKey.address)

expect(lightDid).toEqual({
uri: `did:kilt:light:01${authKey.address}:z15dZSRuzEPTFnBErPxqJie4CmmQH1gYKSQYxmwW5Qhgz5Sr7EYJA3J65KoC5YbgF3NGoBsTY2v6zwj1uDnZzgXzLy8R72Fhjmp8ujY81y2AJc8uQ6s2pVbAMZ6bnvaZ3GVe8bMjY5MiKFySS27qRi`,
uri: `did:kilt:light:01${authKey.address}:z15dZSRuzEZGdAF16HajRyxeLdQCfuYguX3isTjKFteYDVTKCgjbAVK6w4LLjyZxz1BJNMgVYNHBYipdNsKNaNwTcQdE8SueHHdt731pjToNiw56MZyk2Fh3g7xbGNvccLfPfn8MeTWjE9Aw79d8Fr`,
authentication: [
{
id: '#authentication',
Expand Down Expand Up @@ -123,7 +134,7 @@ describe('When creating an instance from the details', () => {

it('throws for unsupported encryption key type', () => {
const authKey = Crypto.makeKeypairFromSeed()
const encKey = Crypto.makeEncryptionKeypairFromSeed()
const encKey = makeEncryptionKeypair()
const invalidInput = {
authentication: [authKey],
// Not an encryption key type
Expand All @@ -140,9 +151,7 @@ describe('When creating an instance from the details', () => {
describe('When creating an instance from a URI', () => {
it('correctly assign the right authentication key, encryption key, and service endpoints', () => {
const authKey = Crypto.makeKeypairFromSeed(undefined, 'sr25519')
const encKey = Crypto.makeEncryptionKeypairFromSeed(
new Uint8Array(32).fill(1)
)
const encKey = makeEncryptionKeypair()
const endpoints: DidServiceEndpoint[] = [
{
id: '#service-1',
Expand All @@ -167,7 +176,7 @@ describe('When creating an instance from a URI', () => {

expect(builtLightDid).toStrictEqual(expectedLightDid)
expect(builtLightDid).toStrictEqual(<DidDocument>{
uri: `did:kilt:light:00${address}:z17GNCdxLqMYTMC5pnnDrPZGxLEFcXvDamtGNXeNkfSaFf8cktX6erFJiQy8S3ugL981NNys7Rz8DJiaNPZi98v1oeFVL7PjUGNTz1g3jgZo4VgQri2SYHBifZFX9foHZH4DreZXFN66k5dPrvAtBpFXaiG2WZkkxsnxNWxYpqWPPcxvbTE6pJbXxWKjRUd7rog1h9vjA93QA9jMDxm6BSGJHACFgSPUU3UTLk2kjNwT2bjZVvihVFu1zibxwHjowb7N6UQfieJ7ny9HnaQy64qJvGqh4NNtpwkhwm5DTYUoAeAhjt3a6TWyxmBgbFdZF7` as DidUri,
uri: `did:kilt:light:00${address}:z17GNCdxLqak5QojTgsFXFzCtSPh9ihEZKDYxcgUb5yjRAz1VtgWiDrRhVLwjgV6cKdPgPpEMFwCfpjjS88gh34Y4Yb7M6aQA1rk62hL15BKtiAdJYieDEaEsYu1Uj7tDUVXFPyEq6j9tKA6xNpT92uYbvveaD9egUdY2htCQN6cL9xvdbCS4Ywrx1vz38NqY1ke3o59zVUw6jahvppwdtqhGiowQhKcHC3d7n2eNtW2rcZ2VmWk63AXkGzmaQUrkkPTqq6erZRXmwk3rmb7tsDuziC44RH22Lbyv9Zp6DddZykmWnHVP7SprWAxmSpQZF` as DidUri,
authentication: [
{
id: '#authentication',
Expand Down Expand Up @@ -199,7 +208,7 @@ describe('When creating an instance from a URI', () => {

it('fail if a fragment is present according to the options', () => {
const authKey = Crypto.makeKeypairFromSeed()
const encKey = Crypto.makeEncryptionKeypairFromSeed()
const encKey = makeEncryptionKeypair()
const service: DidServiceEndpoint[] = [
{
id: '#service-1',
Expand Down
6 changes: 3 additions & 3 deletions packages/did/src/DidResolver/DidResolver.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ describe('When resolving a full DID', () => {

describe('When resolving a light DID', () => {
const authKey = Crypto.makeKeypairFromSeed()
const encryptionKey = Crypto.makeEncryptionKeypairFromSeed()
const encryptionPublicKey = Crypto.hash('', 256)

beforeEach(() => {
// RPC call changed to not return anything by default.
Expand Down Expand Up @@ -477,7 +477,7 @@ describe('When resolving a light DID', () => {
it('correctly resolves the document with authentication key, encryption key, and two service endpoints', async () => {
const lightDid = Did.createLightDidDocument({
authentication: [{ publicKey: authKey.publicKey, type: 'sr25519' }],
keyAgreement: [{ publicKey: encryptionKey.publicKey, type: 'x25519' }],
keyAgreement: [{ publicKey: encryptionPublicKey, type: 'x25519' }],
service: [
generateServiceEndpoint('#service-1'),
generateServiceEndpoint('#service-2'),
Expand All @@ -500,7 +500,7 @@ describe('When resolving a light DID', () => {
{
id: '#encryption',
type: 'x25519',
publicKey: encryptionKey.publicKey,
publicKey: encryptionPublicKey,
},
])
expect(lightDid.service).toStrictEqual<DidServiceEndpoint[]>([
Expand Down
1 change: 0 additions & 1 deletion packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
"@polkadot/util": "^12.0.0",
"@polkadot/util-crypto": "^12.0.0",
"cbor-web": "^9.0.0",
"tweetnacl": "^1.0.3",
"uuid": "^9.0.0"
}
}
46 changes: 0 additions & 46 deletions packages/utils/src/Crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/

import * as string from '@polkadot/util/string'
import nacl from 'tweetnacl'
import * as Crypto from './Crypto'

const messageStr = 'This is a test'
Expand Down Expand Up @@ -116,48 +115,3 @@ describe('helper functions', () => {
`)
})
})

describe('asymmetric crypto', () => {
let alice: nacl.BoxKeyPair
let bob: nacl.BoxKeyPair

beforeAll(() => {
alice = nacl.box.keyPair()
bob = nacl.box.keyPair()
})

it('should encrypt and decrypt asymmetrical (string)', () => {
const encrypted = Crypto.encryptAsymmetricAsStr(
messageStr,
alice.publicKey,
bob.secretKey
)
expect(encrypted).not.toEqual(messageStr)
const decrypted = Crypto.decryptAsymmetricAsStr(
encrypted,
bob.publicKey,
alice.secretKey
)
expect(decrypted).toEqual(messageStr)
const decryptedFalse = Crypto.decryptAsymmetricAsStr(
encrypted,
bob.publicKey,
bob.secretKey
)
expect(decryptedFalse).toEqual(false)
})
it('should encrypt and decrypt asymmetrical (UInt8Array)', () => {
const encrypted = Crypto.encryptAsymmetric(
message,
alice.publicKey,
bob.secretKey
)
expect(encrypted).not.toEqual(message)
const decrypted = Crypto.decryptAsymmetric(
encrypted,
bob.publicKey,
alice.secretKey
)
expect(decrypted).toEqual(message)
})
})
113 changes: 0 additions & 113 deletions packages/utils/src/Crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,13 @@ import { decodeAddress, encodeAddress } from '@polkadot/keyring'
import type {
HexString,
KeyringPair,
KiltEncryptionKeypair,
KiltKeyringPair,
} from '@kiltprotocol/types'
import {
isString,
stringToU8a,
u8aConcat,
u8aToHex,
u8aToString,
u8aToU8a,
} from '@polkadot/util'
import {
Expand All @@ -35,7 +33,6 @@ import {
signatureVerify,
} from '@polkadot/util-crypto'
import { Keyring } from '@polkadot/api'
import nacl from 'tweetnacl'
import { v4 as uuid } from 'uuid'
import jsonabc from './jsonabc.js'
import * as SDKErrors from './SDKErrors.js'
Expand All @@ -45,16 +42,6 @@ export { mnemonicGenerate, mnemonicToMiniSecret } from '@polkadot/util-crypto'

export { encodeAddress, decodeAddress, u8aToHex, u8aConcat }

/**
* Creates a new public/secret box keypair from a secret.
*
* @param secret The secret.
* @returns An object containing a box `publicKey` & `secretKey` generated from the supplied secret.
*/
export function naclBoxPairFromSecret(secret: Uint8Array): nacl.BoxKeyPair {
return nacl.box.keyPair.fromSecretKey(secret)
}

/**
* Types accepted by hashing and crypto functions.
*/
Expand Down Expand Up @@ -179,91 +166,6 @@ export function encodeObjectAsStr(
return input.normalize('NFC')
}

/**
* Wrapper around nacl.box. Authenticated encryption of a message for a recipient's public key.
*
* @param message String or byte array to be encrypted.
* @param publicKeyA Public key of the recipient. The owner will be able to decrypt the message.
* @param secretKeyB Private key of the sender. Necessary to authenticate the message during decryption.
* @returns Encrypted message and nonce used for encryption.
*/
export function encryptAsymmetric(
message: CryptoInput,
publicKeyA: CryptoInput,
secretKeyB: CryptoInput
): EncryptedAsymmetric {
const nonce = nacl.randomBytes(24)
const box = nacl.box(
coToUInt8(message, true),
nonce,
coToUInt8(publicKeyA),
coToUInt8(secretKeyB)
)
return { box, nonce }
}

/**
* Wrapper around nacl.box. Authenticated encryption of a message for a recipient's public key.
*
* @param message String or byte array to be encrypted.
* @param publicKeyA Public key of the recipient. The owner will be able to decrypt the message.
* @param secretKeyB Private key of the sender. Necessary to authenticate the message during decryption.
* @returns Encrypted message and nonce used for encryption as hex strings.
*/
export function encryptAsymmetricAsStr(
message: CryptoInput,
publicKeyA: CryptoInput,
secretKeyB: CryptoInput
): EncryptedAsymmetricString {
const encrypted = encryptAsymmetric(message, publicKeyA, secretKeyB)
const box = u8aToHex(encrypted.box)
const nonce = u8aToHex(encrypted.nonce)
return { box, nonce }
}

/**
* Wrapper around nacl.box.open. Authenticated decryption of an encrypted message.
*
* @param data Object containing encrypted message and nonce used for encryption.
* @param publicKeyB Public key of the sender. Necessary to authenticate the message during decryption.
* @param secretKeyA Private key of the recipient. Required for decryption.
* @returns Decrypted message or false if decryption is unsuccessful.
*/
export function decryptAsymmetric(
data: EncryptedAsymmetric | EncryptedAsymmetricString,
publicKeyB: CryptoInput,
secretKeyA: CryptoInput
): Uint8Array | false {
const decrypted = nacl.box.open(
coToUInt8(data.box),
coToUInt8(data.nonce),
coToUInt8(publicKeyB),
coToUInt8(secretKeyA)
)
return decrypted || false
}

/**
* Wrapper around nacl.box.open. Authenticated decryption of an encrypted message.
*
* @param data Object containing encrypted message and nonce used for encryption.
* @param publicKeyB Public key of the sender. Necessary to authenticate the message during decryption.
* @param secretKeyA Private key of the recipient. Required for decryption.
* @returns Decrypted message as string or false if decryption is unsuccessful.
*/
export function decryptAsymmetricAsStr(
data: EncryptedAsymmetric | EncryptedAsymmetricString,
publicKeyB: CryptoInput,
secretKeyA: CryptoInput
): string | false {
const result = decryptAsymmetric(
data,
coToUInt8(publicKeyB),
coToUInt8(secretKeyA)
)
return result !== false ? u8aToString(result) : false
}

/**
* Signature of hashing function accepted by [[hashStatements]].
*
Expand Down Expand Up @@ -365,18 +267,3 @@ export function makeKeypairFromUri<
const keyring = new Keyring({ ss58Format, type: type ?? 'ed25519' })
return keyring.addFromUri(uri) as KiltKeyringPair & { type: KeyType }
}

/**
* Generate from a seed a x25519 keypair to be used as DID encryption key.
*
* @param seed The keypair seed, only optional in the tests.
* @returns The keypair.
*/
export function makeEncryptionKeypairFromSeed(
seed = randomAsU8a(32)
): KiltEncryptionKeypair {
return {
...naclBoxPairFromSecret(seed),
type: 'x25519',
}
}
4 changes: 0 additions & 4 deletions tests/breakingChanges/BreakingChanges.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,13 @@
*/

import { Did, Utils } from '@kiltprotocol/sdk-js'
import nacl from 'tweetnacl'
import { v4 } from 'uuid'

import { makeKeyAgreement } from '../testUtils/index.js'

jest.mock('uuid')
jest.mocked(v4).mockReturnValue('1ee1307c-9e65-475d-9061-0b5bfd86d2f7')

// Mock nacl randombytes, so that the nonce and ciphertext stay the same between runs
jest.spyOn(nacl, 'randomBytes').mockReturnValue(new Uint8Array(24).fill(42))

function makeLightDidFromSeed(seed: string) {
const keypair = Utils.Crypto.makeKeypairFromUri(seed, 'sr25519')
const keyAgreement = makeKeyAgreement(seed)
Expand Down
Loading

0 comments on commit d7c53aa

Please sign in to comment.