├── .gitignore ├── .gitmodules ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── binding.gyp ├── index.js ├── package.json ├── src ├── mcrypt.cc └── mcrypt.h └── test ├── blowfish-ecb.js ├── main.js └── rijndael-256-cbc.js /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | *.swp 3 | /node_modules/ 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/libmcrypt"] 2 | path = lib/libmcrypt 3 | url = git://github.com/tugrul/libmcrypt-gyp.git 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '10' 4 | - '9' 5 | - '8' 6 | - '7' 7 | - '6' 8 | - '5' 9 | - '4' 10 | - '3' 11 | - '0.12' 12 | sudo: true 13 | before_install: 14 | - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y 15 | - sudo apt-get update -qq 16 | - sudo apt-get install -qq g++-4.8 17 | - export CXX="g++-4.8" CC="gcc-4.8" 18 | script: npm install . && npm test 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Tuğrul Topuz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | __This repository not in active maintain state. Please use [cryptian](https://github.com/tugrul/cryptian) library instead of this library.__ 3 | 4 | 5 | # node-mcrypt [![Build Status](https://travis-ci.org/tugrul/node-mcrypt.svg)](https://travis-ci.org/tugrul/node-mcrypt) 6 | 7 | MCrypt bindings for Node.js 8 | 9 | ## Install 10 | 11 | ``` 12 | npm install mcrypt 13 | ``` 14 | 15 | 16 | ```javascript 17 | var mcrypt = require('mcrypt'); 18 | ``` 19 | 20 | There are 3 exposed common functions in the package. These functions are `getAlgorithmNames()`, `getModeNames()` and `MCrypt()` constructor function. Also there are some functions under the prototype of `MCrypt()` constructor function. 21 | 22 | ### getAlgorithmNames() : Array 23 | 24 | `getAlgorithmNames()` returns an array that contains available algorithm names. 25 | 26 | ```javascript 27 | var mcrypt = require('mcrypt'); 28 | 29 | var algos = mcrypt.getAlgorithmNames(); 30 | console.log(algos); 31 | ``` 32 | 33 | Expected result like that 34 | 35 | ``` 36 | [ 'cast-128', 'gost', 'rijndael-128', 'twofish', 'arcfour', 'cast-256', 'loki97', 'rijndael-192', 'saferplus', 'wake', 'blowfish-compat', 'des', 'rijndael-256', 'serpent', 'xtea', 'blowfish', 'enigma', 'rc2', 'tripledes' ] 37 | ``` 38 | 39 | ### getModeNames() : Array 40 | 41 | `getModeNames()` returns an array that contains available mode names. 42 | 43 | ```javascript 44 | var mcrypt = require('mcrypt'); 45 | 46 | var algos = mcrypt.getModeNames(); 47 | console.log(algos); 48 | ``` 49 | 50 | Expected result like that 51 | ``` 52 | [ 'cbc', 'cfb', 'ctr', 'ecb', 'ncfb', 'nofb', 'ofb', 'stream' ] 53 | ``` 54 | 55 | ### MCrypt(algorithm, mode) : Object 56 | 57 | `MCrypt(algorithm, mode)` is a constructor function to create object for cipher and decipher operations. 58 | `algorithm` is a required parameter and one of the values of array returned by `getAlgorithmNames()`. 59 | `mode` is required parameter and one of the values of array returned by `getModeNames()`. 60 | 61 | ```javascript 62 | var MCrypt = require('mcrypt').MCrypt; 63 | 64 | var desEcb = new MCrypt('des', 'ecb'); 65 | ``` 66 | 67 | There are some prototype functions to make cipher decipher operations and to identify algorithm properties. 68 | 69 | #### open(key [, iv]) 70 | 71 | We are need to `open()` with a key for `decrypt()` and `encrypt()` operations also we should set an iv if required by algorithm in other case `iv` is optional parameter. 72 | `key` and `iv` should be string or Buffer 73 | 74 | ```javascript 75 | var MCrypt = require('mcrypt').MCrypt; 76 | 77 | var desEcb = new MCrypt('des', 'ecb'); 78 | desEcb.open('madepass'); // we are set the key 79 | ``` 80 | 81 | #### encrypt(plaintext) : Buffer 82 | 83 | `encrypt()` returns a Buffer object that contains ciphertext of `plaintext` parameter. `plaintext` parameter should be `string` or `Buffer` 84 | 85 | ```javascript 86 | var MCrypt = require('mcrypt').MCrypt; 87 | 88 | var desEcb = new MCrypt('des', 'ecb'); 89 | desEcb.open('madepass'); // we are set the key 90 | 91 | var ciphertext = desEcb.encrypt('this is top secret message!'); 92 | console.log(ciphertext.toString('base64')); 93 | ``` 94 | 95 | Expected result like that 96 | 97 | ``` 98 | fkJnIgtiH8nsGDryyuIsmyf5vABMGStlpACfKCTifvA= 99 | ``` 100 | 101 | #### decrypt(ciphertext) : Buffer 102 | 103 | `decrypt()` returns a Buffer object that contains plaintext of `ciphertext` parameter. `ciphertext` parameter should be `Buffer` 104 | 105 | ```javascript 106 | var MCrypt = require('mcrypt').MCrypt; 107 | 108 | var desEcb = new MCrypt('des', 'ecb'); 109 | desEcb.open('madepass'); // we are set the key 110 | 111 | var plaintext = desEcb.decrypt(new Buffer('fkJnIgtiH8nsGDryyuIsmyf5vABMGStlpACfKCTifvA=', 'base64')); 112 | console.log(plaintext.toString()); 113 | ``` 114 | 115 | Expected result like that 116 | 117 | ``` 118 | this is top secret message! 119 | ``` 120 | 121 | #### generateIv() : Buffer 122 | 123 | `generateIv()` function generates IV randomly. 124 | 125 | ```javascript 126 | var MCrypt = require('mcrypt').MCrypt; 127 | 128 | var blowfishCfb = new MCrypt('blowfish', 'cfb'); 129 | var iv = blowfishCfb.generateIv(); 130 | 131 | blowfishCfb.open('somekey', iv); 132 | 133 | var ciphertext = blowfishCfb.encrypt('sometext'); 134 | 135 | console.log(Buffer.concat([iv, ciphertext]).toString('base64')); 136 | ``` 137 | 138 | #### validateKeySize(Boolean) 139 | `validateKeySize()` is a function to disable or enable key size validation on `open()` 140 | 141 | ```javascript 142 | var mc = new MCrypt('blowfish', 'ecb'); 143 | mc.validateKeySize(false); // disable key size checking 144 | mc.open('typeconfig.sys^_-'); 145 | ``` 146 | 147 | #### validateIvSize(Boolean) 148 | `validateIvSize()` is a function to disable or enable iv size validation on `open()` 149 | 150 | ```javascript 151 | var mc = new MCrypt('rijndael-256', 'cbc'); 152 | mc.validateIvSize(false); // disable iv size checking 153 | mc.open('$verysec$retkey$', 'foobar'); 154 | ``` 155 | 156 | #### selfTest() : Boolean 157 | 158 | `selfTest()` is an utility function to make test algorithm internally and returns boolean value of status 159 | 160 | ```javascript 161 | var MCrypt = require('mcrypt').MCrypt; 162 | 163 | var blowfishCfb = new MCrypt('blowfish', 'cfb'); 164 | console.log(blowfishCfb.selfTest()); 165 | ``` 166 | 167 | #### isBlockAlgorithmMode() : Boolean 168 | 169 | ```javascript 170 | var MCrypt = require('mcrypt').MCrypt; 171 | 172 | var blowfishCfb = new MCrypt('blowfish', 'cfb'); 173 | console.log(blowfishCfb.isBlockAlgorithmMode()); 174 | ``` 175 | 176 | #### isBlockAlgorithm() : Boolean 177 | 178 | ```javascript 179 | var MCrypt = require('mcrypt').MCrypt; 180 | 181 | var blowfishCfb = new MCrypt('blowfish', 'cfb'); 182 | console.log(blowfishCfb.isBlockAlgorithm()); 183 | ``` 184 | 185 | #### isBlockMode() : Boolean 186 | 187 | ```javascript 188 | var MCrypt = require('mcrypt').MCrypt; 189 | 190 | var blowfishCfb = new MCrypt('blowfish', 'cfb'); 191 | console.log(blowfishCfb.isBlockMode()); 192 | ``` 193 | 194 | #### getBlockSize() : Number 195 | 196 | ```javascript 197 | var MCrypt = require('mcrypt').MCrypt; 198 | 199 | var blowfishCfb = new MCrypt('blowfish', 'cfb'); 200 | console.log(blowfishCfb.getBlockSize()); 201 | ``` 202 | 203 | #### getKeySize() : Number 204 | 205 | ```javascript 206 | var MCrypt = require('mcrypt').MCrypt; 207 | 208 | var blowfishCfb = new MCrypt('blowfish', 'cfb'); 209 | console.log(blowfishCfb.getKeySize()); 210 | ``` 211 | 212 | #### getSupportedKeySizes() : Array 213 | 214 | ```javascript 215 | var MCrypt = require('mcrypt').MCrypt; 216 | 217 | var blowfishCfb = new MCrypt('blowfish', 'cfb'); 218 | console.log(blowfishCfb.getSupportedKeySizes()); 219 | ``` 220 | 221 | #### getIvSize() : Number 222 | 223 | ```javascript 224 | var MCrypt = require('mcrypt').MCrypt; 225 | 226 | var blowfishCfb = new MCrypt('blowfish', 'cfb'); 227 | console.log(blowfishCfb.getIvSize()); 228 | ``` 229 | 230 | #### hasIv() : Boolean 231 | 232 | ```javascript 233 | var MCrypt = require('mcrypt').MCrypt; 234 | 235 | var blowfishCfb = new MCrypt('blowfish', 'cfb'); 236 | console.log(blowfishCfb.hasIv()); 237 | ``` 238 | 239 | #### getAlgorithmName() : String 240 | 241 | ```javascript 242 | var MCrypt = require('mcrypt').MCrypt; 243 | 244 | var blowfishCfb = new MCrypt('blowfish', 'cfb'); 245 | console.log(blowfishCfb.getAlgorithmName()); 246 | ``` 247 | 248 | #### getModeName() : String 249 | 250 | ```javascript 251 | var MCrypt = require('mcrypt').MCrypt; 252 | 253 | var blowfishCfb = new MCrypt('blowfish', 'cfb'); 254 | console.log(blowfishCfb.getModeName()); 255 | ``` 256 | 257 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "mcrypt", 5 | 'dependencies': [ 6 | 'lib/libmcrypt/libmcrypt.gyp:libmcrypt', 7 | ], 8 | "sources": [ 9 | "src/mcrypt.cc" 10 | ], 11 | "include_dirs": [ 12 | "lib/libmcrypt/include/", 13 | "", 11 | "bugs": { 12 | "url": "https://github.com/tugrul/node-mcrypt/issues" 13 | }, 14 | "license": "MIT", 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/tugrul/node-mcrypt.git" 18 | }, 19 | "scripts": { 20 | "test": "mocha" 21 | }, 22 | "engines": { 23 | "node": ">=0.10.16" 24 | }, 25 | "dependencies": { 26 | "bindings": "^1.3.0", 27 | "nan": "^2.14.0" 28 | }, 29 | "devDependencies": { 30 | "mocha": "^2.3.3", 31 | "node-gyp": "^3.6.2" 32 | }, 33 | "main": "index.js", 34 | "gypfile": true 35 | } 36 | -------------------------------------------------------------------------------- /src/mcrypt.cc: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "mcrypt.h" 4 | 5 | using namespace v8; 6 | 7 | Nan::Persistent MCrypt::constructor; 8 | 9 | MCrypt::MCrypt(Nan::NAN_METHOD_ARGS_TYPE info): 10 | checkKeySize(true), 11 | checkIvSize(true), 12 | algo(info[0]), 13 | mode(info[1]) { 14 | 15 | mcrypt_ = mcrypt_module_open(*algo, *mode); 16 | }; 17 | 18 | MCrypt::~MCrypt() { 19 | mcrypt_module_close(mcrypt_); 20 | }; 21 | 22 | 23 | template 24 | char* MCrypt::transform(const char* plainText, size_t* length, int* result) { 25 | const size_t origLength = *length; 26 | 27 | // determine allocation size if the cipher algorithm is block mode 28 | // block mode algorithm needs to fit in modulus of block size 29 | // and it needs to padding space if not fit into block size 30 | if (mcrypt_enc_is_block_algorithm(mcrypt_) == 1) { 31 | size_t blockSize = mcrypt_enc_get_block_size(mcrypt_); 32 | *length = (((*length - 1) / blockSize) + 1) * blockSize; 33 | } 34 | 35 | char* targetData = new char[*length](); 36 | std::copy(plainText, plainText + origLength, targetData); 37 | 38 | // copy of the key and iv due to mcrypt_generic_init not accepts 39 | // const char for key and iv. direct passing is not safe because 40 | // iv and key could be modified by mcrypt_generic_init in this case 41 | char *keyBuf = new char[key.length()]; 42 | key.copy(keyBuf, key.length()); 43 | 44 | char *ivBuf = new char[iv.length()]; 45 | iv.copy(ivBuf, iv.length()); 46 | 47 | if ((*result = mcrypt_generic_init(mcrypt_, keyBuf, key.length(), ivBuf)) < 0) { 48 | delete[] keyBuf; 49 | delete[] ivBuf; 50 | return targetData; 51 | } 52 | 53 | if ((*result = modify(mcrypt_, targetData, *length)) != 0) { 54 | delete[] keyBuf; 55 | delete[] ivBuf; 56 | return targetData; 57 | } 58 | 59 | *result = mcrypt_generic_deinit(mcrypt_); 60 | 61 | delete[] keyBuf; 62 | delete[] ivBuf; 63 | return targetData; 64 | } 65 | 66 | std::vector MCrypt::getKeySizes() { 67 | 68 | int count = 0; 69 | int* sizes = mcrypt_enc_get_supported_key_sizes(mcrypt_, &count); 70 | 71 | if (count <= 0) { 72 | mcrypt_free(sizes); 73 | 74 | size_t size = mcrypt_enc_get_key_size(mcrypt_); 75 | 76 | if (size > 0) { 77 | std::vector keySizes(1); 78 | keySizes[0] = size; 79 | return keySizes; 80 | } 81 | 82 | std::vector keySizes(0); 83 | return keySizes; 84 | } 85 | 86 | std::vector keySizes(count); 87 | 88 | for (int i = 0; i < count; i++) { 89 | keySizes[i] = sizes[i]; 90 | } 91 | 92 | mcrypt_free(sizes); 93 | 94 | return keySizes; 95 | } 96 | 97 | NAN_METHOD(MCrypt::New) { 98 | 99 | if (!info.IsConstructCall()) { 100 | Local argv[] = {info[0], info[1]}; 101 | Local cons = Nan::New(constructor); 102 | return info.GetReturnValue().Set(Nan::NewInstance(cons, 2, argv).ToLocalChecked()); 103 | } 104 | 105 | if (info.Length() < 2) { 106 | Nan::ThrowTypeError("Missing parameters. Algorithm and mode should be specified."); 107 | } 108 | 109 | MCrypt* mcrypt = new MCrypt(info); 110 | 111 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 112 | 113 | mcrypt->Wrap(info.This()); 114 | 115 | return info.GetReturnValue().Set(info.This()); 116 | } 117 | 118 | NAN_METHOD(MCrypt::Open) { 119 | 120 | if (info.Length() < 1) { 121 | Nan::ThrowTypeError("Missing parameter. Key should be specified."); 122 | } 123 | 124 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 125 | 126 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 127 | 128 | if (info[0]->IsString()) { 129 | Nan::Utf8String value(info[0]); 130 | 131 | mcrypt->key = std::string(*value, value.length()); 132 | 133 | } else if (node::Buffer::HasInstance(info[0])) { 134 | 135 | mcrypt->key = std::string(node::Buffer::Data(info[0]), node::Buffer::Length(info[0])); 136 | 137 | } else { 138 | Nan::ThrowTypeError("Key has got incorrect type. Should be Buffer or String."); 139 | } 140 | 141 | 142 | 143 | if (mcrypt->checkKeySize) { 144 | std::vector keySizes = mcrypt->getKeySizes(); 145 | 146 | if (keySizes.size() > 0) { 147 | 148 | bool invalid = true; 149 | 150 | std::stringstream serror; 151 | 152 | serror << "Invalid key size. Available key size are ["; 153 | 154 | for(size_t i = 0; i < keySizes.size(); i++) { 155 | 156 | if (i != 0) { 157 | serror << ", "; 158 | } 159 | 160 | serror << keySizes[i]; 161 | 162 | if (keySizes[i] == mcrypt->key.length()) { 163 | invalid = false; 164 | } 165 | } 166 | 167 | serror << "]"; 168 | 169 | std::string error = serror.str(); 170 | 171 | if (invalid) { 172 | Nan::ThrowTypeError(error.c_str()); 173 | } 174 | } 175 | } 176 | 177 | if (info[1]->IsUndefined()) { 178 | return info.GetReturnValue().SetUndefined(); 179 | } 180 | 181 | size_t ivLen = 0; 182 | 183 | if (info[1]->IsString()) { 184 | 185 | Nan::Utf8String value(info[1]); 186 | 187 | ivLen = value.length(); 188 | mcrypt->iv = std::string(*value, ivLen); 189 | 190 | } else if (node::Buffer::HasInstance(info[1])) { 191 | 192 | ivLen = node::Buffer::Length(info[1]); 193 | mcrypt->iv = std::string(node::Buffer::Data(info[1]), ivLen); 194 | } else { 195 | Nan::ThrowTypeError("Iv has got incorrect type. Should be Buffer or String."); 196 | } 197 | 198 | if (mcrypt->checkIvSize) { 199 | if ((size_t)mcrypt_enc_get_iv_size(mcrypt->mcrypt_) != ivLen) { 200 | Nan::ThrowTypeError("Invalid iv size. You can determine iv size using getIvSize()"); 201 | } 202 | } 203 | 204 | return info.GetReturnValue().SetUndefined(); 205 | } 206 | 207 | // Callback function passed to Nan::NewBuffer() 208 | static void freeCipherText(char *cipherText, void *hint) { 209 | delete[] cipherText; 210 | } 211 | 212 | NAN_METHOD(MCrypt::Encrypt) { 213 | 214 | if (info.Length() < 1) { 215 | Nan::ThrowTypeError("Missing parameter. Plaintext should be specified."); 216 | } 217 | 218 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 219 | 220 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 221 | 222 | int result = 0; 223 | char* cipherText = {0}; 224 | size_t length = 0; 225 | 226 | if (info[0]->IsString()) { 227 | 228 | Nan::Utf8String value(info[0]); 229 | length = value.length(); 230 | cipherText = mcrypt->transform(*value, &length, &result); 231 | 232 | } else if(node::Buffer::HasInstance(info[0])) { 233 | 234 | length = node::Buffer::Length(info[0]); 235 | cipherText = mcrypt->transform(node::Buffer::Data(info[0]), &length, &result); 236 | 237 | } else { 238 | Nan::ThrowTypeError("Plaintext has got incorrect type. Should be Buffer or String."); 239 | } 240 | 241 | if (result != 0) { 242 | const char* error = mcrypt_strerror(result); 243 | delete[] cipherText; 244 | Nan::ThrowError(error); 245 | } 246 | 247 | return info.GetReturnValue().Set(Nan::NewBuffer(cipherText, length, freeCipherText, 0).ToLocalChecked()); 248 | } 249 | 250 | NAN_METHOD(MCrypt::Decrypt) { 251 | 252 | if (info.Length() < 1) { 253 | Nan::ThrowTypeError("Missing parameter. Plaintext should be specified."); 254 | } 255 | 256 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 257 | 258 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 259 | 260 | int result = 0; 261 | char* cipherText = {0}; 262 | size_t length = 0; 263 | 264 | if (info[0]->IsString()) { 265 | 266 | Nan::Utf8String value(info[0]); 267 | length = value.length(); 268 | cipherText = mcrypt->transform(*value, &length, &result); 269 | 270 | } else if (node::Buffer::HasInstance(info[0])) { 271 | length = node::Buffer::Length(info[0]); 272 | cipherText = mcrypt->transform(node::Buffer::Data(info[0]), &length, &result); 273 | 274 | } else { 275 | Nan::ThrowTypeError("Ciphertext has got incorrect type. Should be Buffer or String."); 276 | } 277 | 278 | if (result != 0) { 279 | const char* error = mcrypt_strerror(result); 280 | delete[] cipherText; 281 | Nan::ThrowError(error); 282 | } 283 | 284 | return info.GetReturnValue().Set(Nan::NewBuffer(cipherText, length, freeCipherText, 0).ToLocalChecked()); 285 | } 286 | 287 | NAN_METHOD(MCrypt::ValidateKeySize) { 288 | 289 | if(info.Length() == 0) { 290 | return info.GetReturnValue().SetUndefined(); 291 | } 292 | 293 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 294 | mcrypt->checkKeySize = Nan::Equals(info[0], Nan::True()).FromJust(); 295 | 296 | return info.GetReturnValue().SetUndefined(); 297 | } 298 | 299 | NAN_METHOD(MCrypt::ValidateIvSize) { 300 | 301 | if(info.Length() == 0) { 302 | return info.GetReturnValue().SetUndefined(); 303 | } 304 | 305 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 306 | mcrypt->checkIvSize = Nan::Equals(info[0], Nan::True()).FromJust(); 307 | 308 | return info.GetReturnValue().SetUndefined(); 309 | } 310 | 311 | NAN_METHOD(MCrypt::SelfTest) { 312 | 313 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 314 | 315 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 316 | 317 | if (mcrypt_enc_self_test(mcrypt->mcrypt_) == 0) { 318 | return info.GetReturnValue().Set(Nan::True()); 319 | } 320 | 321 | return info.GetReturnValue().Set(Nan::False()); 322 | } 323 | 324 | NAN_METHOD(MCrypt::IsBlockAlgorithmMode) { 325 | 326 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 327 | 328 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 329 | 330 | if (mcrypt_enc_is_block_algorithm_mode(mcrypt->mcrypt_) == 1) { 331 | return info.GetReturnValue().Set(Nan::True()); 332 | } 333 | 334 | return info.GetReturnValue().Set(Nan::False()); 335 | } 336 | 337 | NAN_METHOD(MCrypt::IsBlockAlgorithm) { 338 | 339 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 340 | 341 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 342 | 343 | if (mcrypt_enc_is_block_algorithm(mcrypt->mcrypt_) == 1) { 344 | return info.GetReturnValue().Set(Nan::True()); 345 | } 346 | 347 | return info.GetReturnValue().Set(Nan::False()); 348 | } 349 | 350 | NAN_METHOD(MCrypt::IsBlockMode) { 351 | 352 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 353 | 354 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 355 | 356 | if (mcrypt_enc_is_block_mode(mcrypt->mcrypt_) == 1) { 357 | return info.GetReturnValue().Set(Nan::True()); 358 | } 359 | 360 | return info.GetReturnValue().Set(Nan::False()); 361 | } 362 | 363 | NAN_METHOD(MCrypt::GetBlockSize) { 364 | 365 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 366 | 367 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 368 | 369 | int blockSize = mcrypt_enc_get_block_size(mcrypt->mcrypt_); 370 | 371 | return info.GetReturnValue().Set(Nan::New(blockSize)); 372 | } 373 | 374 | NAN_METHOD(MCrypt::GetKeySize) { 375 | 376 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 377 | 378 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 379 | 380 | int keySize = mcrypt_enc_get_key_size(mcrypt->mcrypt_); 381 | 382 | return info.GetReturnValue().Set(Nan::New(keySize)); 383 | } 384 | 385 | NAN_METHOD(MCrypt::GetSupportedKeySizes) { 386 | 387 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 388 | 389 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 390 | 391 | std::vector keySizes = mcrypt->getKeySizes(); 392 | 393 | Local array = Nan::New(keySizes.size()); 394 | 395 | for (size_t i = 0; i < keySizes.size(); i++) { 396 | Nan::Set(array, i, Nan::New(keySizes[i])); 397 | } 398 | 399 | return info.GetReturnValue().Set(array); 400 | } 401 | 402 | NAN_METHOD(MCrypt::GetIvSize) { 403 | 404 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 405 | 406 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 407 | 408 | int ivSize = mcrypt_enc_get_iv_size(mcrypt->mcrypt_); 409 | 410 | return info.GetReturnValue().Set(Nan::New(ivSize)); 411 | } 412 | 413 | NAN_METHOD(MCrypt::HasIv) { 414 | 415 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 416 | 417 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 418 | 419 | if (mcrypt_enc_mode_has_iv(mcrypt->mcrypt_) == 1) { 420 | return info.GetReturnValue().Set(Nan::True()); 421 | } 422 | 423 | return info.GetReturnValue().Set(Nan::False()); 424 | } 425 | 426 | NAN_METHOD(MCrypt::GetAlgorithmName) { 427 | 428 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 429 | 430 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 431 | 432 | char* name = mcrypt_enc_get_algorithms_name(mcrypt->mcrypt_); 433 | return info.GetReturnValue().Set(Nan::New(name).ToLocalChecked()); 434 | } 435 | 436 | NAN_METHOD(MCrypt::GetModeName) { 437 | 438 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 439 | 440 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 441 | 442 | char* name = mcrypt_enc_get_modes_name(mcrypt->mcrypt_); 443 | return info.GetReturnValue().Set(Nan::New(name).ToLocalChecked()); 444 | } 445 | 446 | NAN_METHOD(MCrypt::GenerateIv) { 447 | 448 | MCrypt* mcrypt = ObjectWrap::Unwrap(info.This()); 449 | 450 | MCRYPT_MODULE_ERROR_CHECK(mcrypt) 451 | 452 | int ivSize = mcrypt_enc_get_iv_size(mcrypt->mcrypt_); 453 | char* iv = new char[ivSize]; 454 | 455 | for (int i = 0; i < ivSize; i++) { 456 | iv[i] = 255.0 * std::rand() / RAND_MAX; 457 | } 458 | 459 | return info.GetReturnValue().Set(Nan::NewBuffer(iv, ivSize).ToLocalChecked()); 460 | } 461 | 462 | NAN_METHOD(MCrypt::GetAlgorithmNames) { 463 | 464 | int size = 0; 465 | char** algos = mcrypt_list_algorithms(&size); 466 | 467 | Local array = Nan::New(size); 468 | 469 | if (array.IsEmpty()) { 470 | return info.GetReturnValue().Set(Nan::New()); 471 | } 472 | 473 | for (uint32_t i = 0; i < (uint32_t)size; i++) { 474 | Nan::Set(array, i, Nan::New(algos[i]).ToLocalChecked()); 475 | } 476 | 477 | mcrypt_free_p(algos, size); 478 | 479 | return info.GetReturnValue().Set(array); 480 | } 481 | 482 | NAN_METHOD(MCrypt::GetModeNames) { 483 | 484 | int size = 0; 485 | char** modes = mcrypt_list_modes(&size); 486 | 487 | Local array = Nan::New(size); 488 | 489 | if (array.IsEmpty()) 490 | return info.GetReturnValue().Set(Nan::New()); 491 | 492 | for (uint32_t i = 0; i < (uint32_t)size; i++) { 493 | Nan::Set(array, i, Nan::New(modes[i]).ToLocalChecked()); 494 | } 495 | 496 | mcrypt_free_p(modes, size); 497 | 498 | return info.GetReturnValue().Set(array); 499 | } 500 | 501 | void MCrypt::Init(Local exports) { 502 | 503 | Local tpl = Nan::New(New); 504 | tpl->SetClassName(Nan::New("MCrypt").ToLocalChecked()); 505 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 506 | 507 | // prototype 508 | Nan::SetPrototypeMethod(tpl, "encrypt", Encrypt); 509 | Nan::SetPrototypeMethod(tpl, "decrypt", Decrypt); 510 | Nan::SetPrototypeMethod(tpl, "open", Open); 511 | Nan::SetPrototypeMethod(tpl, "validateKeySize", ValidateKeySize); 512 | Nan::SetPrototypeMethod(tpl, "validateIvSize", ValidateIvSize); 513 | Nan::SetPrototypeMethod(tpl, "selfTest", SelfTest); 514 | Nan::SetPrototypeMethod(tpl, "isBlockAlgorithmMode", IsBlockAlgorithmMode); 515 | Nan::SetPrototypeMethod(tpl, "isBlockAlgorithm", IsBlockAlgorithm); 516 | Nan::SetPrototypeMethod(tpl, "isBlockMode", IsBlockMode); 517 | Nan::SetPrototypeMethod(tpl, "getBlockSize", GetBlockSize); 518 | Nan::SetPrototypeMethod(tpl, "getKeySize", GetKeySize); 519 | Nan::SetPrototypeMethod(tpl, "getSupportedKeySizes", GetSupportedKeySizes); 520 | Nan::SetPrototypeMethod(tpl, "getIvSize", GetIvSize); 521 | Nan::SetPrototypeMethod(tpl, "hasIv", HasIv); 522 | Nan::SetPrototypeMethod(tpl, "getAlgorithmName", GetAlgorithmName); 523 | Nan::SetPrototypeMethod(tpl, "getModeName", GetModeName); 524 | Nan::SetPrototypeMethod(tpl, "generateIv", GenerateIv); 525 | 526 | // exports 527 | constructor.Reset(Nan::GetFunction(tpl).ToLocalChecked()); 528 | Nan::Set(exports, Nan::New("MCrypt").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked()); 529 | Nan::SetMethod(exports, "getAlgorithmNames", GetAlgorithmNames); 530 | Nan::SetMethod(exports, "getModeNames", GetModeNames); 531 | } 532 | 533 | NODE_MODULE(mcrypt, MCrypt::Init) 534 | -------------------------------------------------------------------------------- /src/mcrypt.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef SRC_NODE_MCRYPT_H_ 3 | #define SRC_NODE_MCRYPT_H_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #define MCRYPT_MODULE_ERROR_CHECK(mcrypt) \ 13 | if (mcrypt->mcrypt_ == MCRYPT_FAILED) { \ 14 | Nan::ThrowError("MCrypt module could not open"); \ 15 | } 16 | 17 | using namespace v8; 18 | 19 | class MCrypt : public node::ObjectWrap { 20 | public: 21 | static void Init(Local exports); 22 | 23 | private: 24 | MCrypt(Nan::NAN_METHOD_ARGS_TYPE args); 25 | ~MCrypt(); 26 | 27 | template 28 | char* transform(const char* plainText, size_t* length, int* result); 29 | 30 | std::vector getKeySizes(); 31 | 32 | static Nan::Persistent constructor; 33 | 34 | static NAN_METHOD(New); 35 | static NAN_METHOD(Encrypt); 36 | static NAN_METHOD(Decrypt); 37 | static NAN_METHOD(Open); 38 | static NAN_METHOD(ValidateKeySize); 39 | static NAN_METHOD(ValidateIvSize); 40 | static NAN_METHOD(SelfTest); 41 | static NAN_METHOD(IsBlockAlgorithmMode); 42 | static NAN_METHOD(IsBlockAlgorithm); 43 | static NAN_METHOD(IsBlockMode); 44 | static NAN_METHOD(GetBlockSize); 45 | static NAN_METHOD(GetKeySize); 46 | static NAN_METHOD(GetSupportedKeySizes); 47 | static NAN_METHOD(GetIvSize); 48 | static NAN_METHOD(HasIv); 49 | static NAN_METHOD(GetAlgorithmName); 50 | static NAN_METHOD(GetModeName); 51 | static NAN_METHOD(GenerateIv); 52 | static NAN_METHOD(Close); 53 | 54 | static NAN_METHOD(GetAlgorithmNames); 55 | static NAN_METHOD(GetModeNames); 56 | 57 | MCRYPT mcrypt_; 58 | std::string key; 59 | std::string iv; 60 | 61 | bool checkKeySize; 62 | bool checkIvSize; 63 | 64 | Nan::Utf8String algo; 65 | Nan::Utf8String mode; 66 | }; 67 | 68 | #endif // ~ SRC_NODE_MCRYPT_H_ 69 | -------------------------------------------------------------------------------- /test/blowfish-ecb.js: -------------------------------------------------------------------------------- 1 | 2 | var mcrypt = require('..'); 3 | var assert = require('assert'); 4 | 5 | describe('MCrypt instance (BLOWFISH-ECB)', function() { 6 | var mc = new mcrypt.MCrypt('blowfish', 'ecb'); 7 | 8 | it('should be an object', function() { 9 | assert(typeof mc == 'object', 'there is an object'); 10 | }); 11 | 12 | describe('open', function() { 13 | var key = 'YpQ3SXbNe9O/Vca/h+FVKQ=='; 14 | var plaintext = '1165096\0'; 15 | var ciphertext = 'LRo7D+VTxVw='; 16 | 17 | it('should open without error', function() { 18 | assert.doesNotThrow(function() { 19 | mc.validateKeySize(false); 20 | mc.open(new Buffer(key, 'base64')); 21 | }, 'there is error when opened with key'); 22 | }); 23 | 24 | describe('encrypt', function() { 25 | it('plaintext and decrypted ciphertext should be same', function(){ 26 | assert.equal(ciphertext, mc.encrypt(plaintext).toString('base64'), 'ciphertext are not same'); 27 | 28 | }); 29 | }); 30 | 31 | describe('decrypt', function() { 32 | it('ciphertext and encrypted plaintext should be same', function(){ 33 | var result = mc.decrypt(new Buffer(ciphertext, 'base64')).toString(); 34 | assert.equal(plaintext, result, 'plaintext are not same'); 35 | }); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/main.js: -------------------------------------------------------------------------------- 1 | 2 | var mcrypt = require('..'); 3 | var assert = require('assert'); 4 | 5 | describe('MCrypt', function() { 6 | 7 | describe('getAlgorithmNames', function() { 8 | it('should be a function', function() { 9 | assert(typeof mcrypt.getAlgorithmNames == 'function', 'there is getAlgorithmNames function'); 10 | }); 11 | 12 | it('should return an array', function() { 13 | assert(mcrypt.getAlgorithmNames() instanceof Array, 'there is an array'); 14 | }); 15 | 16 | it('should some values in the array', function() { 17 | assert(mcrypt.getAlgorithmNames().length > 0, 'there are some values'); 18 | }); 19 | 20 | it('should be DES value in the array', function() { 21 | assert(mcrypt.getAlgorithmNames().indexOf('des') > -1, 'there is the des value'); 22 | }); 23 | }); 24 | 25 | describe('getModeNames', function(){ 26 | it('should be a function', function() { 27 | assert(typeof mcrypt.getModeNames == 'function', 'there is getModeNames function'); 28 | }); 29 | 30 | it('should return an array', function() { 31 | assert(mcrypt.getModeNames() instanceof Array, 'there is an array'); 32 | }); 33 | 34 | it('should some values in the array', function() { 35 | assert(mcrypt.getModeNames().length > 0, 'there are some values'); 36 | }); 37 | 38 | it('should be ECB value in the array', function() { 39 | assert(mcrypt.getModeNames().indexOf('ecb') > -1, 'there is the ecb value'); 40 | }); 41 | }); 42 | 43 | 44 | describe('constructor', function() { 45 | it('should be a constructor function', function() { 46 | assert(typeof mcrypt.MCrypt == 'function', 'there is MCrypt constructor function'); 47 | }); 48 | 49 | it('should throw exception without parameters', function() { 50 | assert.throws(function(){ 51 | new mcrypt.MCrypt(); // without algo and mode 52 | }, Error, 'there is a TypeError when parameters are missed'); 53 | }); 54 | 55 | it('should throw exception with less parameter', function(){ 56 | assert.throws(function(){ 57 | new mcrypt.MCrypt('des'); // without mode 58 | }); 59 | }); 60 | 61 | it('should throw exception with wrong parameters', function() { 62 | assert.throws(function(){ 63 | new mcrypt.MCrypt('deso', 'ecb'); // invalid algo name 64 | }, Error, 'there is a ReferenceError when parameters are wrong'); 65 | 66 | assert.throws(function(){ 67 | new mcrypt.MCrypt('des', 'ebo'); // invalid mode name 68 | }, Error, 'there is a ReferenceError when parameters are wrong'); 69 | }); 70 | 71 | it('should not throw exception with correct parameters', function() { 72 | assert.doesNotThrow(function() { 73 | new mcrypt.MCrypt('des', 'ecb'); 74 | }, 'there is no error when parameters are correct'); 75 | }); 76 | }); 77 | 78 | describe('MCrypt instance (BLOWFISH-ECB)', function() { 79 | var mc = new mcrypt.MCrypt('blowfish', 'ecb'); 80 | 81 | it('should be an object', function() { 82 | assert(typeof mc == 'object', 'there is an object'); 83 | }); 84 | 85 | describe('open', function() { 86 | var key = 'typeconfig.sys^_-'; 87 | 88 | it('should open without error', function() { 89 | assert.doesNotThrow(function() { 90 | mc.validateKeySize(false); 91 | mc.open(key); 92 | }, 'there is error when opened with key'); 93 | }); 94 | }); 95 | }); 96 | 97 | describe('MCrypt instance (DES-ECB)', function() { 98 | var mc = new mcrypt.MCrypt('des', 'ecb'); 99 | 100 | it('should be an object', function() { 101 | assert(typeof mc == "object", 'there is an object'); 102 | }); 103 | 104 | describe('open', function() { 105 | var key = 'madepass'; 106 | var plaintext = 'top secret information!!'; 107 | var ciphertext = '7Bg68sriLJuKCYPl1NmSwGrBrE0E5I+T'; 108 | 109 | it('should open without error', function(){ 110 | assert.doesNotThrow(function(){ 111 | mc.open(key); 112 | }, 'there is error when opened with key'); 113 | }); 114 | 115 | describe('encrypt', function() { 116 | it('plaintext and decrypted ciphertext should be same', function(){ 117 | assert.equal(ciphertext, mc.encrypt(plaintext).toString('base64'), 'ciphertext are not same'); 118 | }); 119 | 120 | }); 121 | 122 | describe('decrypt', function() { 123 | it('ciphertext and encrypted plaintext should be same', function(){ 124 | assert.equal(plaintext, mc.decrypt(new Buffer(ciphertext, 'base64')).toString(), 'plaintext are not same'); 125 | }); 126 | }); 127 | 128 | // describe('selfTest', function(){ 129 | // it('should return true', function(){ 130 | // assert(mc.selfTest(), 'return value is not true'); 131 | // }); 132 | // }); 133 | 134 | describe('isBlockAlgorithmMode', function(){ 135 | it('should return true', function(){ 136 | assert(mc.isBlockAlgorithmMode(), 'return value is not true'); 137 | }); 138 | }); 139 | 140 | describe('isBlockAlgorithm', function(){ 141 | it('should return true', function(){ 142 | assert(mc.isBlockAlgorithm(), 'return value is not true'); 143 | }); 144 | }); 145 | 146 | describe('isBlockMode', function(){ 147 | it('should return true', function(){ 148 | assert(mc.isBlockMode(), 'return value is not true'); 149 | }); 150 | }); 151 | 152 | describe('getKeySize', function(){ 153 | it('should equal to keysize of algorithm', function(){ 154 | assert.equal(mc.getKeySize(), 8, 'return value is not 8'); 155 | }); 156 | }); 157 | 158 | describe('getSupportedKeySizes', function(){ 159 | it('should return an array', function() { 160 | assert(mc.getSupportedKeySizes() instanceof Array, 'return value is not array'); 161 | }); 162 | 163 | it('array should not be empty', function() { 164 | assert(mc.getSupportedKeySizes().length > 0, 'return value is empty'); 165 | }); 166 | }); 167 | 168 | describe('getIvSize', function(){ 169 | it('should equal to iv size of algorithm', function(){ 170 | assert.equal(mc.getIvSize(), 8, 'iv size not equals to 8'); 171 | }); 172 | }); 173 | 174 | describe('generateIv', function(){ 175 | it('should equal to iv size of algorithm', function(){ 176 | assert.equal(mc.generateIv().length, 8, 'iv size not equals to 8'); 177 | }); 178 | }); 179 | 180 | describe('hasIv', function(){ 181 | it('should return false', function(){ 182 | assert.equal(mc.hasIv(), false, 'return value is not false'); 183 | }); 184 | }); 185 | 186 | describe('getAlgorithmName', function(){ 187 | it('should return DES', function(){ 188 | assert.equal(mc.getAlgorithmName(), 'DES', 'return value is not DES'); 189 | }); 190 | }); 191 | 192 | describe('getModeName', function() { 193 | it('should return ECB', function(){ 194 | assert.equal(mc.getModeName(), 'ECB', 'return value is not ECB'); 195 | }); 196 | }); 197 | 198 | }); 199 | 200 | 201 | }); 202 | }); 203 | 204 | -------------------------------------------------------------------------------- /test/rijndael-256-cbc.js: -------------------------------------------------------------------------------- 1 | 2 | var mcrypt = require('..'); 3 | var assert = require('assert'); 4 | 5 | describe('MCrypt instance (RIJNDAEL-256-CBC)', function() { 6 | var mc = new mcrypt.MCrypt('rijndael-256', 'cbc'); 7 | 8 | it('should be an object', function() { 9 | assert(typeof mc == 'object', 'there is an object'); 10 | }); 11 | 12 | describe('open', function() { 13 | var key = '32charteststring32charteststring'; 14 | var plaintext = 'super secret stuff. super secret'; 15 | var ciphertext = 'bpbeXZrsbiTtMsIRxNBNBA+9ZViHZObhak42fLgmPQg='; 16 | var iv = '1mTHy+gyVcNGjXmgXYLy6aK2JJoEPSLNJ2YhG/43gtU='; 17 | 18 | it('should open without error', function() { 19 | assert.doesNotThrow(function() { 20 | mc.validateKeySize(false); 21 | mc.open(key, new Buffer(iv, 'base64')); 22 | }, 'there is error when opened with key'); 23 | }); 24 | 25 | describe('encrypt', function() { 26 | it('plaintext and decrypted ciphertext should be same', function(){ 27 | assert.equal(ciphertext, mc.encrypt(plaintext).toString('base64'), 'ciphertext are not same'); 28 | 29 | }); 30 | }); 31 | 32 | describe('decrypt', function() { 33 | it('ciphertext and encrypted plaintext should be same', function(){ 34 | assert.equal(plaintext, mc.decrypt(new Buffer(ciphertext, 'base64')).toString().trim(), 'plaintext are not same'); 35 | }); 36 | }); 37 | }); 38 | }); 39 | --------------------------------------------------------------------------------