-
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 #12 from frytg/dev/crypto-key-base64
Dev/crypto key base64
- Loading branch information
Showing
13 changed files
with
343 additions
and
70 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
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,16 @@ | ||
/** | ||
* @module | ||
* Run key generation for default key sizes and print the results to the console | ||
* | ||
* @example | ||
* ```bash | ||
* deno run jsr:@frytg/crypto/generate-default-keys | ||
* ``` | ||
*/ | ||
|
||
// load module | ||
import { generateKey } from './generate-key.ts' | ||
|
||
generateKey(32) | ||
generateKey(64) | ||
generateKey(128) |
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,71 @@ | ||
// load packages | ||
import { Buffer } from 'node:buffer' | ||
import { test } from '@cross/test' | ||
import { assertEquals, assertExists } from '@std/assert' | ||
|
||
// load module | ||
import { generateKey } from './generate-key.ts' | ||
|
||
test('generateKey - generates keys of correct length', () => { | ||
const testCases = [{ bytes: 16 }, { bytes: 32 }, { bytes: 64 }, { bytes: 128 }] | ||
|
||
for (const { bytes } of testCases) { | ||
const key = generateKey(bytes, true) | ||
|
||
// Check buffer length | ||
assertEquals(key.buffer.length, bytes, `Buffer should be ${bytes} bytes long`) | ||
|
||
// Check hex length (2 characters per byte) | ||
assertEquals(key.hex.length, bytes * 2, `Hex string should be ${bytes * 2} characters long`) | ||
} | ||
}) | ||
|
||
test('generateKey - generates different keys each time', () => { | ||
const keys = new Set() | ||
const numKeys = 100 | ||
const bytes = 32 | ||
|
||
// Generate multiple keys | ||
for (let i = 0; i < numKeys; i++) { | ||
const key = generateKey(bytes, true) | ||
keys.add(key.hex) | ||
} | ||
|
||
// All keys should be unique | ||
assertEquals(keys.size, numKeys, `All ${numKeys} generated keys should be unique`) | ||
}) | ||
|
||
test('generateKey - returns consistent encodings', () => { | ||
const key = generateKey(32, true) | ||
|
||
// Buffer to base64 | ||
assertEquals(key.base64, key.buffer.toString('base64'), 'base64 encoding should match Buffer.toString("base64")') | ||
|
||
// Buffer to hex | ||
assertEquals(key.hex, key.buffer.toString('hex'), 'hex encoding should match Buffer.toString("hex")') | ||
|
||
// base64 back to buffer | ||
assertEquals(Buffer.from(key.base64, 'base64'), key.buffer, 'base64 string should convert back to original buffer') | ||
|
||
// hex back to buffer | ||
assertEquals(Buffer.from(key.hex, 'hex'), key.buffer, 'hex string should convert back to original buffer') | ||
}) | ||
|
||
test('generateKey - uses default length of 32 bytes', () => { | ||
const key = generateKey(undefined, true) | ||
assertEquals(key.buffer.length, 32, 'Default key length should be 32 bytes') | ||
}) | ||
|
||
test('generateKey - returns object with required properties', () => { | ||
const key = generateKey(32, true) | ||
|
||
// Check that all properties exist | ||
assertExists(key.buffer, 'Should have buffer property') | ||
assertExists(key.base64, 'Should have base64 property') | ||
assertExists(key.hex, 'Should have hex property') | ||
|
||
// Check property types | ||
assertEquals(key.buffer instanceof Buffer, true, 'buffer should be Buffer instance') | ||
assertEquals(typeof key.base64, 'string', 'base64 should be string') | ||
assertEquals(typeof key.hex, 'string', 'hex should be string') | ||
}) |
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,57 @@ | ||
// deno-lint-ignore-file no-console | ||
/** | ||
* @module | ||
* {@linkcode generateKey | Generate a key} | ||
* | ||
* @example | ||
* ```ts | ||
* import { generateKey } from '@frytg/crypto/generate-key' | ||
* | ||
* generateKey(32, true) | ||
* ``` | ||
*/ | ||
|
||
// demo provided by | ||
// https://cloud.google.com/storage/docs/encryption/using-customer-supplied-keys#storage-generate-encryption-key-nodejs | ||
|
||
// load packages | ||
import type { Buffer } from 'node:buffer' | ||
import crypto from 'node:crypto' | ||
|
||
/** | ||
* Generates a key of the specified number of bytes and prints the key in base64 and hex to the console | ||
* | ||
* @param {number} bytes - The number of bytes to generate | ||
* @param {boolean} skipConsole - Whether to skip printing to the console | ||
* @returns {Object} The key in base64 and hex | ||
* | ||
* @example | ||
* ```ts | ||
* import { generateKey } from '@frytg/crypto/generate-key' | ||
* | ||
* generateKey(32, true) | ||
* ``` | ||
*/ | ||
export const generateKey = (bytes = 32, skipConsole = false): { buffer: Buffer; base64: string; hex: string } => { | ||
// generate key | ||
if (!skipConsole) console.group(`Generating ${bytes} byte key...\n`) | ||
|
||
// generate key | ||
const buffer = crypto.randomBytes(bytes) | ||
|
||
// encode key in base64 | ||
const encodedKeyBase64 = buffer.toString('base64') | ||
if (!skipConsole) console.log(`Base 64 encoded key:\n${encodedKeyBase64}\n`) | ||
|
||
// encode key in hex | ||
const encodedKeyHex = buffer.toString('hex') | ||
if (!skipConsole) console.log(`Hex encoded key:\n${encodedKeyHex}\n`) | ||
|
||
if (!skipConsole) console.groupEnd() | ||
|
||
return { | ||
buffer, | ||
base64: encodedKeyBase64, | ||
hex: encodedKeyHex, | ||
} | ||
} |
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,122 @@ | ||
// load packages | ||
import { Buffer } from 'node:buffer' | ||
import { test } from '@cross/test' | ||
import { assertEquals, assertThrows } from '@std/assert' | ||
|
||
// load module | ||
import { bufferFromBase64, bufferFromHex } from './hmac.ts' | ||
|
||
test('bufferFromBase64 - converts base64 strings to Buffer correctly', () => { | ||
const testCases = [ | ||
{ | ||
input: 'aGVsbG8=', // "hello" | ||
expected: Buffer.from('hello'), | ||
}, | ||
{ | ||
input: '', // empty string | ||
expected: Buffer.from(''), | ||
}, | ||
{ | ||
input: 'YWJjZGVmMTIzNDU2', // "abcdef123456" | ||
expected: Buffer.from('abcdef123456'), | ||
}, | ||
{ | ||
input: 'Zm9vIGJhcg==', // "foo bar" | ||
expected: Buffer.from('foo bar'), | ||
}, | ||
] | ||
|
||
for (const { input, expected } of testCases) { | ||
assertEquals(bufferFromBase64(input), expected, `bufferFromBase64("${input}") should return correct Buffer`) | ||
} | ||
}) | ||
|
||
test('bufferFromBase64 - validates valid base64 strings correctly', () => { | ||
// Valid base64 strings should work | ||
const validBase64 = [ | ||
'aGVsbG8=', // normal case | ||
'', // empty string | ||
'YQ==', // single char padding | ||
'YWI=', // double char padding | ||
'YWJj', // no padding needed | ||
'YWJjZA==', // standard padding | ||
] | ||
|
||
for (const base64 of validBase64) { | ||
assertEquals( | ||
typeof bufferFromBase64(base64), | ||
'object', | ||
`bufferFromBase64 should accept valid base64 string "${base64}".`, | ||
) | ||
} | ||
}) | ||
|
||
test('bufferFromBase64 - validates invalid base64 strings correctly', () => { | ||
// Invalid base64 strings should throw | ||
const invalidBase64 = [ | ||
'!@#$', // invalid characters | ||
'hello', // not base64 | ||
'YW JjZA==', // spaces | ||
] | ||
|
||
for (const base64 of invalidBase64) { | ||
assertThrows( | ||
() => bufferFromBase64(base64), | ||
Error, | ||
'base64', // error message should include | ||
`bufferFromBase64 should reject invalid base64 string "${base64}".`, | ||
) | ||
} | ||
}) | ||
|
||
test('bufferFromHex - converts hex strings to Buffer correctly', () => { | ||
const testCases = [ | ||
{ | ||
input: '0123456789abcdef', | ||
expected: Buffer.from([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]), | ||
}, | ||
{ | ||
input: 'ff00ff00', | ||
expected: Buffer.from([0xff, 0x00, 0xff, 0x00]), | ||
}, | ||
{ | ||
input: '', | ||
expected: Buffer.from([]), | ||
}, | ||
] | ||
|
||
for (const { input, expected } of testCases) { | ||
assertEquals(bufferFromHex(input), expected, `bufferFromHex("${input}") should return correct Buffer`) | ||
} | ||
}) | ||
|
||
test('bufferFromHex - validates valid hex strings correctly', () => { | ||
// Valid hex strings should work | ||
const validHexes = ['0123456789abcdef', 'ABCDEF', '', '00', 'ff', 'deadbeef'] | ||
|
||
for (const hex of validHexes) { | ||
assertEquals(typeof bufferFromHex(hex), 'object', `bufferFromHex should accept valid hex string "${hex}"`) | ||
} | ||
}) | ||
|
||
test('bufferFromHex - validates invalid hex strings correctly', () => { | ||
// Invalid hex strings should throw | ||
const invalidHexes = [ | ||
'0123456789abcdefg', // invalid hex char | ||
'0123456789abcdef0', // odd length | ||
'xyz', // non-hex chars | ||
'gh', // non-hex chars | ||
' ', // whitespace | ||
'12 34', // spaces | ||
'12-34', // dashes | ||
] | ||
|
||
for (const hex of invalidHexes) { | ||
assertThrows( | ||
() => bufferFromHex(hex), | ||
Error, | ||
'Invalid hex string', // error message should include | ||
`bufferFromHex should reject invalid hex string "${hex}"`, | ||
) | ||
} | ||
}) |
Oops, something went wrong.