Skip to content

Commit

Permalink
add @devicescript/crypto
Browse files Browse the repository at this point in the history
  • Loading branch information
mmoskal committed Jun 20, 2023
1 parent ee8a688 commit 4e07577
Show file tree
Hide file tree
Showing 17 changed files with 641 additions and 146 deletions.
8 changes: 6 additions & 2 deletions bytecode/bytecode.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ For a more highlevel description of runtime and bytecode, see [Runtime implement

img_version_major = 2
img_version_minor = 12
img_version_patch = 1
img_version_patch = 2
img_version = $version
magic0 = 0x53766544 // "DevS"
magic1 = 0xf1296e0a
Expand Down Expand Up @@ -711,4 +711,8 @@ Only `true` and `false` values.
mode = 210
capabilities = 211
value = 212
setMode = 213
setMode = 213
fillRandom = 214
encrypt = 215
decrypt = 216
digest = 217
14 changes: 11 additions & 3 deletions compiler/src/bytecode.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions devs/run-tests/allcompile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import "@devicescript/drivers"
import "@devicescript/gpio"
import "@devicescript/spi"
import "@devicescript/graphics"
import "@devicescript/crypto"
import "@devicescript/net"
import "@devicescript/runtime"

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@
"test:cloud": "cd packages/cloud && yarn test",
"test:settings": "cd packages/settings && yarn test",
"test:i2c": "cd packages/i2c && yarn test",
"test:crypto": "cd packages/crypto && yarn test",
"test:graphics": "cd packages/graphics && yarn test",
"test:ros": "cd packages/ros && yarn test",
"test:snippets": "node ./cli/devicescript snippets",
"test:sampleprj": "node ./scripts/buildsampleprj.mjs",
"test": "yarn test:compiler && yarn test:test && yarn test:runtime && yarn test:settings && yarn test:i2c && yarn test:observables && yarn test:ros && yarn test:cloud && yarn test:sampleprj && yarn test:snippets && yarn test:graphics && yarn test:cowsay",
"test": "yarn test:compiler && yarn test:test && yarn test:runtime && yarn test:settings && yarn test:i2c && yarn test:observables && yarn test:ros && yarn test:cloud && yarn test:sampleprj && yarn test:snippets && yarn test:crypto && yarn test:graphics && yarn test:cowsay",
"boards": "node ./cli/devicescript ctool --fetch-boards compiler/src/boards.json",
"bump": "node scripts/bump.mjs",
"hwdocs": "node scripts/genhwsupport.mjs",
Expand Down
17 changes: 17 additions & 0 deletions packages/crypto/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# @devicescript/crypto

[DeviceScript](https://microsoft.github.io/devicescript/) cryptographic algorithms (AES, SHA) support.

- [Read documentation](https://microsoft.github.io/devicescript/developer/crypto)

## Contributing

Contributions are welcome! See [contributing page](../../CONTRIBUTING.md).

## Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
trademarks or logos is subject to and must follow
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
Any use of third-party trademarks or logos are subject to those third-party's policies.
1 change: 1 addition & 0 deletions packages/crypto/devsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
41 changes: 41 additions & 0 deletions packages/crypto/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "@devicescript/crypto",
"version": "2.12.1",
"private": true,
"dependencies": {},
"devDependencies": {
"@devicescript/cli": "*"
},
"repository": {
"type": "git",
"url": "https://github.com/microsoft/devicescript.git",
"directory": "packages/crypto"
},
"scripts": {
"setup": "devicescript build",
"build:devicescript": "devicescript build src/main.ts -F allFunctions",
"build": "yarn build:devicescript",
"watch:devicescript": "devicescript devtools src/main.ts",
"watch": "yarn watch:devicescript",
"test:devicescript": "devicescript run src/main.ts --test --test-self-exit -F allFunctions",
"test": "yarn test:devicescript",
"start": "yarn watch"
},
"main": "./src/index.ts",
"license": "MIT",
"devicescript": {
"bundle": true,
"library": true
},
"files": [
"src/*.ts",
"devsconfig.json"
],
"keywords": [
"devicescript"
],
"author": "Microsoft",
"publishConfig": {
"access": "public"
}
}
148 changes: 148 additions & 0 deletions packages/crypto/src/crypto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import * as ds from "@devicescript/core"

export type SymmetricAlgorithm = "aes-256-ccm"
export type HashAlgorithm = "sha256"

export interface CipherOptions {
/**
* Data to be encrypted or decrypted.
*/
data: Buffer

/**
* Algorithm to use.
*/
algo: SymmetricAlgorithm

/**
* Key, has to be of the right size for the algorithm.
* For AES256 key length is 256 bits, so 32 bytes.
* @see keySize()
*/
key: Buffer

/**
* Nonce/initialization vector - use a random one for every message!
* For AES-CCM this is 13 bytes.
* @see ivSize()
*/
iv: Buffer

/**
* For authenticated encryption, the length of the tag that is appended at the end of the cipher-text.
*/
tagLength: 0 | 4 | 8 | 16
}

/**
* Return the expected key buffer size for a given algorithm.
*/
export function keySize(algo: SymmetricAlgorithm) {
if (algo === "aes-256-ccm") return 32
return undefined
}

/**
* Return the expected IV (nonce) buffer size for a given algorithm.
*/
export function ivSize(algo: SymmetricAlgorithm) {
if (algo === "aes-256-ccm") return 13
return undefined
}

function expectBuffer(v: Buffer, lbl: string, len?: number) {
if (!(v instanceof Buffer))
throw new TypeError(`expecting ${lbl} buffer, got ${v}`)
if (len !== undefined && v.length !== len)
throw new TypeError(
`expecting ${lbl} buffer to be ${len}, not ${v.length}`
)
}

function validateOptions(options: CipherOptions) {
const { algo } = options
if (algo !== "aes-256-ccm")
throw new TypeError(`invalid symm algo: ${options.algo}`)
expectBuffer(options.data, "data")
expectBuffer(options.key, "key", keySize(algo))
expectBuffer(options.iv, "iv", ivSize(algo))
switch (options.tagLength) {
case 0:
case 4:
case 8:
case 16:
break
default:
throw new TypeError(`invalid tagLength ${options.tagLength}`)
}
}

/**
* Encrypt a plain text buffer.
*/
export function encrypt(options: CipherOptions): Buffer {
validateOptions(options)
return (options.data as any).encrypt(
options.algo,
options.key,
options.iv,
options.tagLength
)
}

/**
* Decrypt a cipher-text buffer.
*/
export function decrypt(options: CipherOptions): Buffer {
validateOptions(options)
return (options.data as any).encrypt(
options.algo,
options.key,
options.iv,
0x1000 + options.tagLength
)
}

/**
* Fill buffer with cryptographically strong random values
*/
export function getRandom(size: number): Buffer {
const r = Buffer.alloc(size)
;(r as any).fillRandom()
return r
}

function validateHash(algo: HashAlgorithm) {
if (algo !== "sha256") throw new TypeError(`invalid hash: ${algo}`)
}

/**
* Compute digest (hash) of the concatenation of the specified buffers.
*/
export function digest(algo: HashAlgorithm, ...data: Buffer[]): Buffer {
validateHash(algo)
return (Buffer as any).digest(undefined, algo, data)
}

/**
* Compute HMAC digest (authenticated hash) of the concatenation of the specified buffers.
*/
export function hmac(
key: Buffer,
algo: HashAlgorithm,
...data: Buffer[]
): Buffer {
validateHash(algo)
expectBuffer(key, "key")
return (Buffer as any).digest(key, algo, data)
}

export function sha256Hkdf(
salt: Buffer,
key: Buffer,
info: Buffer,
info2: Buffer = hex``
) {
const outkey = hmac(salt, "sha256", key)
return hmac(outkey, "sha256", info, info2, hex`01`)
}
1 change: 1 addition & 0 deletions packages/crypto/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./crypto"
Loading

0 comments on commit 4e07577

Please sign in to comment.