Skip to content

Instantly share code, notes, and snippets.

@PyYoshi
Last active June 6, 2017 12:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PyYoshi/84ca60df4585712bc388a1f2987ca841 to your computer and use it in GitHub Desktop.
Save PyYoshi/84ca60df4585712bc388a1f2987ca841 to your computer and use it in GitHub Desktop.
Browser/NodeJSでSHAダイジェストを行うためのライブラリ
// Chrome以外でも利用する場合は以下をimportすること
// import 'webcrypto-shim';
import JSSHA from 'jssha';
function webCryptoHex(buffer: Uint8Array): string {
const hexCodes = [];
const view = new DataView(buffer);
for (let i = 0; i < view.byteLength; i += 4) {
const value = view.getUint32(i);
const stringValue = value.toString(16);
const padding = '00000000';
const paddedValue = (padding + stringValue).slice(-padding.length);
hexCodes.push(paddedValue);
}
return hexCodes.join('');
}
type WebCryptoDigestAlgorithm = 'SHA-1' | 'SHA-256' | 'SHA-512';
function webCryptoDigestString(algorithm: WebCryptoDigestAlgorithm, str: string): Promise<string> {
const buffer = new TextEncoder('utf-8').encode(str);
return crypto.subtle.digest(algorithm, buffer).then((hash) => webCryptoHex(hash));
}
type NodeJSDigestAlgorithm = 'sha1' | 'sha256' | 'sha512';
function nodejsDigestString(algorithm: NodeJSDigestAlgorithm, str: string): Promise<string> {
return new Promise((resolve) => {
const crypto = require('crypto'); // eslint-disable-line
const shasum = crypto.createHash(algorithm);
shasum.update(str);
resolve(shasum.digest('hex'));
});
}
type jsSHADigestAlgorithm = 'SHA-1' | 'SHA-256' | 'SHA-512';
function jsSHADigestString(algorithm: jsSHADigestAlgorithm, str: string): Promise<string> {
return new Promise((resolve) => {
const shasum = new JSSHA(algorithm, 'TEXT');
shasum.update(str);
resolve(shasum.getHash('HEX'));
});
}
function isNodeJS(): boolean {
return typeof window === 'undefined' && typeof process === 'object';
}
function hasWebCrypto(): boolean {
return typeof window !== 'undefined' && typeof window.crypto !== 'undefined';
}
function isSecureOrigin(): boolean {
if (typeof window !== 'undefined' && typeof window.isSecureContext === 'boolean') {
return window.isSecureContext;
}
return typeof window !== 'undefined' && window.location.protocol === 'https:';
}
export function sha1(str: string): Promise<string> {
if (isNodeJS()) {
return nodejsDigestString('sha1', str);
}
if (isSecureOrigin() && hasWebCrypto()) {
return webCryptoDigestString('SHA-1', str);
}
return jsSHADigestString('SHA-1', str);
}
export function sha256(str: string): Promise<string> {
if (isNodeJS()) {
return nodejsDigestString('sha256', str);
}
if (isSecureOrigin() && hasWebCrypto()) {
return webCryptoDigestString('SHA-256', str);
}
return jsSHADigestString('SHA-256', str);
}
export function sha512(str: string): Promise<string> {
if (isNodeJS()) {
return nodejsDigestString('sha512', str);
}
if (isSecureOrigin() && hasWebCrypto()) {
return webCryptoDigestString('SHA-512', str);
}
return jsSHADigestString('SHA-512', str);
}
// Chrome以外でも利用する場合は以下をimportすること
// import 'webcrypto-shim';
import JSSHA from 'jssha';
function webCryptoHex(buffer) {
const hexCodes = [];
const view = new DataView(buffer);
for (let i = 0; i < view.byteLength; i += 4) {
const value = view.getUint32(i);
const stringValue = value.toString(16);
const padding = '00000000';
const paddedValue = (padding + stringValue).slice(-padding.length);
hexCodes.push(paddedValue);
}
return hexCodes.join('');
}
function webCryptoDigestString(algorithm, str) {
const buffer = new TextEncoder('utf-8').encode(str);
return crypto.subtle.digest(algorithm, buffer).then(hash => webCryptoHex(hash));
}
function nodejsDigestString(algorithm, str) {
return new Promise(resolve => {
const crypto = require('crypto'); // eslint-disable-line
const shasum = crypto.createHash(algorithm);
shasum.update(str);
resolve(shasum.digest('hex'));
});
}
function jsSHADigestString(algorithm, str) {
return new Promise(resolve => {
const shasum = new JSSHA(algorithm, 'TEXT');
shasum.update(str);
resolve(shasum.getHash('HEX'));
});
}
function isNodeJS() {
return typeof window === 'undefined' && typeof process === 'object';
}
function hasWebCrypto() {
return typeof window !== 'undefined' && typeof window.crypto !== 'undefined';
}
function isSecureOrigin() {
if (typeof window !== 'undefined' && typeof window.isSecureContext === 'boolean') {
return window.isSecureContext;
}
return typeof window !== 'undefined' && window.location.protocol === 'https:';
}
export function sha1(str) {
if (isNodeJS()) {
return nodejsDigestString('sha1', str);
}
if (isSecureOrigin() && hasWebCrypto()) {
return webCryptoDigestString('SHA-1', str);
}
return jsSHADigestString('SHA-1', str);
}
export function sha256(str) {
if (isNodeJS()) {
return nodejsDigestString('sha256', str);
}
if (isSecureOrigin() && hasWebCrypto()) {
return webCryptoDigestString('SHA-256', str);
}
return jsSHADigestString('SHA-256', str);
}
export function sha512(str) {
if (isNodeJS()) {
return nodejsDigestString('sha512', str);
}
if (isSecureOrigin() && hasWebCrypto()) {
return webCryptoDigestString('SHA-512', str);
}
return jsSHADigestString('SHA-512', str);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment