Skip to content

Commit

Permalink
feat: use base64 to encode sha256 hash (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Jul 14, 2022
1 parent fd56689 commit 778413f
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 10 deletions.
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ const { hash, objectHash, murmurHash, sha256 } = require('ohash')

### `hash(object, options?)`

Converts object value into a string hash using `objectHash` and then applies `sha256` (trimmed by length of 10).
Converts object value into a string hash using `objectHash` and then applies `sha256` with Base64 encoding (trimmed by length of 10).

Usage:

```js
import { hash } from 'ohash'

// "7596ed03b7"
console.log(hash({ foo: 'bar'}))
// "dZbtA7f0lK"
console.log(hash({ foo: 'bar' }))
```

### `objectHash(object, options?)`
Expand Down Expand Up @@ -83,6 +83,17 @@ import { sha256 } from 'ohash'
console.log(sha256('Hello World'))
```

### `sha256base64`

Create a secure [SHA 256](https://en.wikipedia.org/wiki/SHA-2) digest in Base64 encoding from input string.

```js
import { sha256base64 } from 'ohash'

// "pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4"
console.log(sha256base64('Hello World'))
```

## 💻 Development

- Clone this repository
Expand Down
24 changes: 21 additions & 3 deletions src/crypto/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class WordArray {
return (encoder || Hex).stringify(this)
}

concat (wordArray) {
concat (wordArray: WordArray) {
// Clamp excess bits
this.clamp()

Expand Down Expand Up @@ -53,9 +53,9 @@ export class WordArray {
}

export const Hex = {
stringify (wordArray) {
stringify (wordArray: WordArray) {
// Convert
const hexChars = []
const hexChars: string[] = []
for (let i = 0; i < wordArray.sigBytes; i++) {
const bite = (wordArray.words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xFF
hexChars.push((bite >>> 4).toString(16))
Expand All @@ -66,6 +66,24 @@ export const Hex = {
}
}

export const Base64 = {
stringify (wordArray: WordArray) {
const keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
const base64Chars: string[] = []
for (let i = 0; i < wordArray.sigBytes; i += 3) {
const byte1 = (wordArray.words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xFF
const byte2 = (wordArray.words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xFF
const byte3 = (wordArray.words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xFF

const triplet = (byte1 << 16) | (byte2 << 8) | byte3
for (let j = 0; (j < 4) && (i * 8 + j * 6 < wordArray.sigBytes * 8); j++) {
base64Chars.push(keyStr.charAt((triplet >>> (6 * (3 - j))) & 0x3F))
}
}
return base64Chars.join('')
}
}

export const Latin1 = {
parse (latin1Str) {
// Shortcut
Expand Down
6 changes: 5 additions & 1 deletion src/crypto/sha256.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Based on https://github.com/brix/crypto-js 4.1.1 (MIT)

import { WordArray, Hasher } from './core'
import { WordArray, Hasher, Base64 } from './core'

// Initialization and round constants tables
const H = [1779033703, -1150833019, 1013904242, -1521486534, 1359893119, -1694144372, 528734635, 1541459225]
Expand Down Expand Up @@ -110,3 +110,7 @@ export class SHA256 extends Hasher {
export function sha256 (message: string) {
return new SHA256().finalize(message).toString()
}

export function sha256base64 (message: string) {
return new SHA256().finalize(message).toString(Base64)
}
4 changes: 2 additions & 2 deletions src/hash.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { objectHash, HashOptions } from './object-hash'
import { sha256 } from './crypto/sha256'
import { sha256base64 } from './crypto/sha256'

/**
* Hash any JS value into a string
Expand All @@ -10,5 +10,5 @@ import { sha256 } from './crypto/sha256'
*/
export function hash (object: any, options: HashOptions = {}): string {
const hashed = typeof object === 'string' ? object : objectHash(object, options)
return sha256(hashed).substr(0, 10)
return sha256base64(hashed).substr(0, 10)
}
8 changes: 7 additions & 1 deletion test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { expect, it } from 'vitest'
import { murmurHash, objectHash, hash, sha256 } from '../src'
import { sha256base64 } from '../src/crypto/sha256'

it('murmurHash', () => {
expect(murmurHash('Hello World')).toMatchInlineSnapshot('2708020327')
Expand All @@ -10,10 +11,15 @@ it('sha256', () => {
expect(sha256('')).toMatchInlineSnapshot('"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"')
})

it('sha256base64', () => {
expect(sha256base64('Hello World')).toMatchInlineSnapshot('"pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4"')
expect(sha256base64('')).toMatchInlineSnapshot('"47DEQpj8HBSaTImW5JCeuQeRkm5NMpJWZG3hSuFU"')
})

it('objectHash', () => {
expect(objectHash({ foo: 'bar' })).toMatchInlineSnapshot('"object:1:string:3:foo:string:3:bar,"')
})

it('hash', () => {
expect(hash({ foo: 'bar' })).toMatchInlineSnapshot('"7596ed03b7"')
expect(hash({ foo: 'bar' })).toMatchInlineSnapshot('"dZbtA7f0lK"')
})

0 comments on commit 778413f

Please sign in to comment.