Code Monkey home page Code Monkey logo

jscrypto's Introduction

jscrypto

npm version License: MIT Build

crypto-js enhancement for modern js environments.

  • Works in modern browsers and IE9/10/11.
    *IE9/10 uses weak random generator on cipher encryption with string password. Use it at your own risk.
    *If only using decryption or hash/hmac, weak random generator does not cause any trouble.
  • Loadable with ES6/CommonJS/Typescript/Browser runtimes.
  • Support GCM/GMAC/CCM/CBC-MAC ๐ŸŽ‰๐ŸŽ‰๐ŸŽ‰
  • CLI commands available:
    i.e. npx jscrypto sha1 "message", npx jscrypto aes enc "message" "password", etc.
  • Written in Typescript with rich type declarations.
  • When bundling only SHA256 module, the webpack-ed js file can be less than 6kb.
  • Default parameters for Block cipher (AES/DES/Triple-DES) is tuned to be OpenSSL(1.1.1f) compatible.
    Read further here

Breaking changes for version 0.x.x users

There are several breaking changes between version 0.x and 1.x.
Please see detail in CHANGELOG

Install

npm install jscrypto
# or
yarn add jscrypto

If you only want to use CLI commands, you don't even need to install jscrypto.
Just dispatch npx command like npx jscrypto sha256 "message".
Read further here

Usage

CommonJS Environment (Node.js environment like node CLI, AWS Lambda, etc)

// Load whole library modules.
const JsCrypto = require("jscrypto");
console.log(JsCrypto.SHA256.hash("test").toString());

// or load only necessary modules (Recommended for faster loading and reduced size)
const {SHA256} = require("jscrypto/SHA256");
console.log(SHA256.hash("test").toString());

ES6 Environment (i.e. Creating app/library with webpack/react-scripts or some es6-compatible bundlers)

Be sure to load the module from jscrypto/es6.
This can greatly reduce bundle size by bundlers tree-shaking ability. Don't forget to add /es6 following jscrypto

// Load whole library modules.
import * as JsCrypto from "jscrypto/es6";
console.log(JsCrypto.SHA256.hash("test").toString());
...
import {SHA256} from "jscrypto/es6/SHA256"; // Recommended
console.log(SHA256.hash("test").toString());

Typescript Environment

Be sure to load the module from jscrypto/es6.

// Load whole library modules.
import * as JsCrypto from "jscrypto/es6";
console.log(JsCrypto.SHA256.hash("test").toString());
...
import {SHA256} from "jscrypto/es6/SHA256"; // Recommended
console.log(SHA256.hash("test").toString());

Browser

Copy js files/directories under /dist dir into somewhere browser can access.
Then directly load js file into <script> tag.

<script src="dist/index.js"></script> <!-- All modules are loaded into browser -->
<script type="text/javascript">
  // This will output: "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
  console.log(JsCrypto.SHA256.hash("test").toString());
</script>
<!-- OR -->
<script src="dist/SHA256.js"></script> <!-- Single module loading is lightweight and faster. -->
<script type="text/javascript">
  // This will output: "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
  console.log(JsCrypto.SHA256.hash("test").toString());
</script>

CLI

Command Line Interface to try various crypto modules on terminal.

  Usage: npx jscrypto <hash|hmac|cipher> [command options]

  hash: md5, sha1, sha3, sha224, sha256, sha384, sha512, ripemd160
  hmac: hmac-md5, hmac-sha1, hmac-sha224, hmac-sha256, hmac-sha384, hmac-sha512
  cipher: aes, des, des3, rc4

  
  $ npx jscrypto <hash> message [-msg hex|base64|utf8] [-out hex|base64]

    default:
      -msg: utf8 ... recognize message as utf-8 string
      -out: hex ... output hashed binary as hex string
    example:
      #Output of below 3 examples are the same
      npx jscrypto sha1 test
      npx jscrypto sha1 74657374 -msg hex
      npx jscrypto sha1 dGVzdA== -msg base64


  $ npx jscrypto <hmac> message key [msg hex|base64|utf8] [-key hex|base64|utf8] [-out hex|base64]

    default:
      -msg: utf8 ... recognize message as utf-8 string
      -key: utf8 ... recognize key as utf-8 string
      -out: hex ... output hashed binary as hex string
    example:
      #Output of below 3 examples are the same
      npx jscrypto hmac-sha1 test key
      npx jscrypto hmac-sha1 74657374 6b6579 -msg hex -key hex
      npx jscrypto hmac-sha1 dGVzdA== a2V5 -msg base64 -key base64


  $ npx jscrypto <cipher> message key [-msg hex|base64|utf8] [-key hex|base64|utf8] [-out hex|base64|utf8] [-mode cbc|ecb|ofb|cfb] [-pad pkcs7|iso10126|iso97971|ansix923|nopadding] [-kdf pbkdf2|evpkdf]

    default:
      -msg: utf8 ... recognize message as utf-8 string
      -key: utf8 ... recognize key as utf-8 string
      -out: base64|hex ... base64 on encryption, hex on decryption. Note: utf8 cannot be used on encryption.
      -mode: cbc ... Code block chaining as block cipher mode
      -pad: pkcs7 ... Pkcs7 padding as block padding
      -kdf: pbkdf2 ... PBKDF2 as key derivation function
    example:
      #Encrypt (Output would not be the same because of a random salt, but can be decrypted with the same key)
      npx jscrypto aes enc test password
      npx jscrypto aes enc 74657374 70617373776f7264 -msg hex -key hex
      npx jscrypto aes enc dGVzdA== cGFzc3dvcmQ= -msg base64 -key base64
      #Decrypt
      npx jscrypto aes dec U2FsdGVkX19Kf/wItWMuaTrQYV3OljA3Cr9WPMhC6Tk= password -out utf8
      npx jscrypto aes dec A2pYDd/3oeENsRFGA1Y0Mg== 70617373776f7264 -key hex -out utf8
      npx jscrypto aes dec A2pYDd/3oeENsRFGA1Y0Mg== cGFzc3dvcmQ= -key base64 -out utf8

OpenSSL compatibility

Encryption

encryptedData = JsCrypto.AES.encrypt("message", "secret phrase").toString();

is equivalent in OpenSSL (1.1.1f) to

echo -n "message" | openssl enc -e -aes-256-cbc -pass pass:"secret phrase" -base64 -pbkdf2
# Note: Because of a random salt, everytime it produces different base64 string.
# But it is OK for decryption.

Decryption

Encrypted data can be decrypted by

JsCrypto.AES.decrypt(encryptedData, "secret phrase").toString(JsCrypto.Utf8); // "message"

or in OpenSSL

echo "U2FsdGVkX1..." | openssl enc -d -aes-256-cbc -pass pass:"secret phrase" -base64 -pbkdf2
# U2FsdGVkX1... is the output from either JsCrypto/OpenSSL encryption code/command.

FAQ

Failed to import jscrypto in Typescript environment.

In most cases, your tsconfig.json is configured not to load npm module from node_modules folder.
Check your tsconfig.js to be:

{
  "compilerOptions": {
    "moduleResolution": "Node"
  }
}

API

jscrypto supports crypto modules as well as cryptojs.

Popular

Hash MD5, SHA1, SHA3, SHA224, SHA256, SHA384, SHA512, RIPEMD160,
Message/Key Hash HMAC-MD5, HMAC-SHA224, HMAC-SHA256, HMAC-SHA384, HMAC-SHA512, GMAC, CBC-MAC
Block Cipher AES, DES, Triple-DES

Basic structure

Word Word32Array, Word64Array
Encoder Base64, Hex, Latin1, Utf8, Utf16

Misc

Stream Cipher Rabbits, RC4, RC4Drop
Key Derive Function OpenSSLKDF, EvpKDF, PBKDF2
Block Cipher mode CBC, CFB, CTR, ECB, OFB, GCM, CCM
Block Padding AnsiX923, ISO10126, ISO97971, NoPadding, Pkcs7, Zero
Formatter OpenSSLFormatter

jscrypto's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

jscrypto's Issues

AES GCM decrypts only part

I know you're probably not working on this anymore, but I'm hoping you'll at least see this message and might have an idea where I can look.

I'm trying to decrypt data using AES GCM. I can do this in node js perfectly fine and I've almost got it working in your library. I can authenticate the data and key using the AAD and tag, which works great. Then I can decrypt the payload, but it never decrypts the whole message, only a small part.

Full disclosure, I'm trying to decrypt the broadcast messages from Tuya devices, so I can (eventually) use them in an app called SignalRGB. I know how to do this in NodeJS, but their app only supports limited JS. So that's why I'm here. Your library is the only one so far that has been able to decrypt at least part of the data.

Here's a test script, assuming you import AES, MD5, GCM, Hex and Base64

const aad = Hex.parse('00000000000000000013000000f1');
const tag = Hex.parse('36521b69183234690ed71b27fea429b5');

const key = MD5.hash('yGAdlopoPVldABfn');
const payloadBase64 = 'gkfGIQ1HGkmfHBwFqN9mtmz0bWGMVIhllyfMdXM0GnnEu4FYtSeSVumBoNg6yQ0Zvy6vzZhrjpLheWVHwVrytFj1GXNqesVv2u0lyTuaaKtt41epfZbTJ53CUMCFiOyXBjJZlFzHDLVWdwNd6697JT5WVclT8LML7dQ1ZCRJ2RTRoccqa+qbXPtkuyknC6EqwfttCOlshpOB6eKNf0+mG8ZKPIAFIGKIorI/OZgsGy5o4sijBtbJzh9jGQQCp2hPwc57PXqmCnmzA7kvYJkt9XFW+DCS';
const payload = Base64.parse(payloadBase64);

const iv = Hex.parse('7dc8a528c958e1359c7b08ad');

var authtag = GCM.mac(AES, key, iv, aad, payload);

// Let's see if the data is correct
if (authtag.toString() !== tag.toString())
{
    console.log('Error authenticating data');
} else
{
    console.log('Key and data is valid');
    console.log(payload);
    console.log(payload.toString(Base64));

    let decrypted = AES.decrypt(payload.toString(Base64), key, {iv: iv, mode: GCM});
    console.log('Decrypted', decrypted);   
}

This is a 213 byte long encrypted json message. If I decrypt it in node js, it gives me exactly that. A 213 byte decrypted json message. When I use your library it gives me, in this case, 15 bytes of the decrypted json message. So it does decrypt correctly, it just stops randomly.

I have other examples where the library decrypts more, but never the full message. Do you have any clue where I should look?

Best regards,
Rick

JsCrypto AES GCM Encrypted String not decrypted in Java code.

Javascript code

var salt = JsCrypto.Utf8.parse("abcd");
var iv = JsCrypto.Utf8.parse("DuWObJpjGijl6mxB");

var password = "0Usd2xqrLnjXJjcMKFb2T6SrWTag8FSXzAIfnHCIY24="
var plainText = "test";

var keySize = 256;
var iterations = 1;
var options = {
iv: iv,
mode: JsCrypto.mode.GCM,
padding: JsCrypto.pad.Pkcs7,
}

function generateKey(passphrase, salt) {
var key = JsCrypto.PBKDF2.getKey(
passphrase ,
salt,
{ keySize: keySize, iterations: iterations }
);
return key;
}

function encrypt(word) {
var key1= generateKey(password,salt);
var encrypted = JsCrypto.AES.encrypt(word, key1, options);
return encrypted.cipherText.toString(JsCrypto.Base64);
// return ciphertext.toString();
}

function decrypt(word) {
var key1= generateKey(password,salt);
var decrypt = JsCrypto.AES.decrypt(word, key1, options);
return JsCrypto.Utf8.stringify(decrypt).toString();
}

var encryptTxt = encrypt(plainText);
console.log(encryptTxt)

var decryptTxt = decrypt(encryptTxt);

console.log(decryptTxt)

Output
nj0XaL1LnSgQHw/bCFW/2A==
test

Java Code
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.spec.KeySpec;
import java.util.Base64;

public class NewGcmTry {
private static final String DEFAULT_CIPHER_ALGORITHM = "AES/GCM/NoPadding";
private static final int GCM_TAG_LENGTH = 128;
private static final int GCM_IV_LENGTH = 12;
private static final int SALT_LENGTH = 16;
private static final Charset UTF_8 = StandardCharsets.UTF_8;

public static String encrypt(byte[] pText, String password) {
    try {
        byte[] salt = "abcd".getBytes();
        byte[] iv = "DuWObJpjGijl6mxB".getBytes();

      SecretKey aesKeyFromPassword = getSecretKey(password.toCharArray(),salt);

        Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
        GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
        cipher.init(Cipher.ENCRYPT_MODE,aesKeyFromPassword ,gcmParameterSpec);
        byte[] result = cipher.doFinal(pText);
        return Base64.getEncoder().encodeToString(result);
    } catch (Exception ex) {
        System.out.println(ex);

// logger.error("encrypt error", ex);
}
return null;
}

public static void main(String[] args) {
     String password = "0Usd2xqrLnjXJjcMKFb2T6SrWTag8FSXzAIfnHCIY24=";
     String plainText = "test";
    String encrypt = NewGcmTry.encrypt(plainText.getBytes(StandardCharsets.UTF_8), password);
    System.out.println(encrypt);
}


private static SecretKey getSecretKey(char[] password, byte[] salt) {
    try {

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec spec = new PBEKeySpec(password, salt, 1, 256); //65536
        SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
        return secret;
    } catch (Exception ex) {
        System.out.println(ex);
    }
    return null;
}

}

Output
BYY3sot+nIXRX0x3a52OW55/kVg=

Kindly help to find similar code for java also.

I wanted to created encrypted text in Javascript and decrypt in Java.

Thanks in advance !

Specifying KeySizes while encryption and decryption...

While decryption am getting the half of the encrypted data only... compared to the .NET BouncyCastle GCM encryption...
In BouncyCastle am getting encrypted data having length 32 whereas in the jsCrypto am getting 16...
i cant get the references in the document that provided either in npm js or in the gist...

Here is the configuration...
let encryptedData = jsCrypto.AES.encrypt(
msg,
key,{
iv:iv,
mode: jsCrypto.mode.GCM,
padding: jsCrypto.pad.NoPadding
}
);

es6 build needs to use mjs file extension or specify `"type": "module"` in a parent `package.json` file.

Without this, more strict bundlers and Node's ESM mode won't be able to import the es6 build of jscrypto.

e.g. From vitest:

SyntaxError: Cannot use import statement outside a module
Module .../node_modules/.pnpm/[email protected]/node_modules/jscrypto/es6/lib/random.js:1 seems to be an ES Module but shipped in a CommonJS package. You might want to create an issue to the package "jscrypto" asking them to ship the file in .mjs extension or add "type": "module" in their package.json.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.