title: Convert DESede/ECB/NoPadding algorithm written in java into Nodejs using crypto module
body: <p>I am working on migration of code form java to Nodejs. I have one requirement to encrypt the text with private key using "DESede/ECB/NoPadding" algorithm. Currently code is written in Java and now I need to migrate to Nodejs. Since encrypted key is sent to other application therefore I can't change the algorithm or key here. Following is approach used in java</p>
  
  <pre><code>1. Stored the private key in hex string. I.e. 48 chars hex string as below which is equivalent to 24 bytes reuquired for 3des
  73AD9CEC99816AA6A4D82FB273AD9CEC99816AA6A4D82FB2
  2. Following is code written in java 
  https://github.com/dilipkumar2k6/3des/blob/master/TripleDes.java
  import java.security.GeneralSecurityException;
  
  import javax.crypto.Cipher;
  import javax.crypto.spec.SecretKeySpec;
  
  
  public class TripleDes {
      // Crypto library related keys
      private static final String ALGO_NAME = "DESede/ECB/NoPadding";
      private static final int PADDING_BLOCK = 8;
  
      // Test Data
      private static final String PLAIN_TEXT = "Hello World";
      private static final String SHARED_KEY = "73AD9CEC99816AA6A4D82FB273AD9CEC99816AA6A4D82FB2";
  
      public static void main(String[] arg) {
  
          try {
              // Get Algorithm name
              String desAlgoName = getDESAlgorithmName(ALGO_NAME);
              // Create Cipher object
              Cipher cipher = Cipher.getInstance(ALGO_NAME);
              //Actual DES algo needs 56 bits key, which is equivalent to 1byte (0 at 0th position)  Get 8*3 byets key
              byte [] key = hexFromString(SHARED_KEY);
              System.out.println("DES Algorithm  shared key size in bytes &gt;&gt; "+key.length);
              // Create SecretKeySpec
              SecretKeySpec secretKeySpec = new SecretKeySpec(key, desAlgoName);
              //Encrypt bytes
              byte [] encryptedBytes = encryptIntoBytes(cipher, secretKeySpec, PLAIN_TEXT.getBytes(), 0, PLAIN_TEXT.getBytes().length);
              String encryptedString=  hexToString(encryptedBytes);
              System.out.println(encryptedString);
  
          } catch (Exception e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
      }
  
      public static byte[] encryptIntoBytes(Cipher cipher, SecretKeySpec secretKeySpec, byte[] dct, int offset, int len) throws GeneralSecurityException {
          cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
          byte[] ect = cipher.doFinal(addPadding(dct, offset, len));
          return ect;
      }
  
      public static String getDESAlgorithmName(String algoName) {
          System.out.println("getDESAlgorithmName algoName &gt;&gt; "+algoName);
          String desAlgoName = null;
          int i = algoName.indexOf("/");
          if (i != -1)
              desAlgoName = algoName.substring(0, i);
          else
              desAlgoName = algoName;
          return desAlgoName;
      }
  
      /**
       * Adds padding characters to the data to be encrypted. Also adds random
       * Initial Value to the beginning of the encrypted data when using Triple
       * DES in CBC mode (DES-EDE3/CBC).
       * 
       * @param inData
       *            Array of bytes to be padded
       * @param offset
       *            Offset to starting point within array
       * @param len
       *            Number of bytes to be encrypted
       * @return Padded array of bytes
       */
      public static byte[] addPadding(byte[] inData, int offset, int len) {
          System.out.println("addPadding offset &gt;&gt; "+offset+", len &gt;&gt; "+len);
          byte[] bp = null;
          int padChars = PADDING_BLOCK; // start with max padding value
          int partial = (len + 1) % padChars; // calculate how many extra bytes
                                              // exist
          if (partial == 0) {
              padChars = 1; // if none, set to only pad with length byte
          } else {
              padChars = padChars - partial + 1; // calculate padding size to
                                                  // include length
          }
          System.out.println("addPadding &gt;&gt; Add padding of "+padChars);
          /*
           * Create a byte array large enough to hold data plus padding bytes The
           * count of padding bytes is placed in the first byte of the data to be
           * encrypted. That byte is included in the count.
           */
          bp = new byte[len + padChars];
          bp[0] = Byte.parseByte(Integer.toString(padChars));
          System.arraycopy(inData, offset, bp, 1, len);
          return bp;
      }
  
      public static byte[] hexFromString(String hex) {
          int len = hex.length();
          byte[] buf = new byte[((len + 1) / 2)];
  
          int i = 0, j = 0;
          if ((len % 2) == 1)
              buf[j++] = (byte) fromDigit(hex.charAt(i++));
  
          while (i &lt; len) {
              buf[j++] = (byte) ((fromDigit(hex.charAt(i++)) &lt;&lt; 4) | fromDigit(hex
                      .charAt(i++)));
          }
          return buf;
      }
  
      public static int fromDigit(char ch) {
          if (ch &gt;= '0' &amp;&amp; ch &lt;= '9')
              return ch - '0';
          if (ch &gt;= 'A' &amp;&amp; ch &lt;= 'F')
              return ch - 'A' + 10;
          if (ch &gt;= 'a' &amp;&amp; ch &lt;= 'f')
              return ch - 'a' + 10;
  
          throw new IllegalArgumentException("invalid hex digit '" + ch + "'");
      }
  
      public static String hexToString(byte[] ba) {
          return hexToString(ba, 0, ba.length);
      }
  
      public static final char[] hexDigits = { '0', '1', '2', '3', '4', '5',
              '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
  
      public static String hexToString(byte[] ba, int offset, int length) {
          char[] buf = new char[length * 2];
          int j = 0;
          int k;
  
          for (int i = offset; i &lt; offset + length; i++) {
              k = ba[i];
              buf[j++] = hexDigits[(k &gt;&gt;&gt; 4) &amp; 0x0F];
              buf[j++] = hexDigits[k &amp; 0x0F];
          }
          return new String(buf);
      }
  
  }
  </code></pre>
  
  <p>I need to migrate this code to Nodejs and facing multiple issues. I refeered <a href="http://mygo.iteye.com/blog/2018882" rel="nofollow">http://mygo.iteye.com/blog/2018882</a> to get the basic idea on nodejs way to do the encryption in des3. However I see following difference in JAVA way and Nodejs way.</p>
  
  <pre><code>1. JAVA is using Hex string of 48 lenght as key, since one char in hex is 4 bits therfore final size is equivalent to 24 bytes length which meets DES3 requirement. 
  2. In Java code, final key is being used as bytes (as needed by DES) which made indpendent of the way we store the key
  3. In node js, key is stored as character i.e. to use des3 I have to use 24 bytes which is equivalent to 24 chars key as  73AD9CEC99816AA6A4D82FB2. Here this is string of 24 chars and since one char is one byte thereofore total length is 24 bytes which meets DES3 requirement.
  4. Following is nodejs code for reference
  https://github.com/dilipkumar2k6/3des/blob/master/Crypto.js
  'use strict';
  /*
   *  Offers related services.
   */
  var crypto = require("crypto");
  
  module.exports = {
      encrypt: function (plainText) {
          return encrypt({
              alg: 'des-ede3', //3des-ecb  
              autoPad: true,
              key: '73AD9CEC99816AA6A4D82FB2',
              plaintext: 'Hello World',
              iv: null
          });
      }
  };
  
  function encrypt(param) {
      var key = new Buffer(param.key);
      var iv = new Buffer(param.iv ? param.iv : 0);
      var plaintext = param.plaintext;
      var alg = param.alg;
      var autoPad = param.autoPad;
  
      //encrypt  
      var cipher = crypto.createCipheriv(alg, key, iv);
      cipher.setAutoPadding(autoPad);  //default true  
      var ciph = cipher.update(plaintext, 'utf8', 'hex');
      ciph += cipher.final('hex');
      console.log(alg, ciph);
      return ciph;
  
  }
  
  function decrypt(param) {
      var key = new Buffer(param.key);
      var iv = new Buffer(param.iv ? param.iv : 0)
      var alg = param.alg;
      var autoPad = param.autoPad;
  
      //decrypt  
      var decipher = crypto.createDecipheriv(alg, key, iv);
      cipher.setAutoPadding(autoPad);
      var txt = decipher.update(ciph, 'hex', 'utf8');
      txt += decipher.final('utf8');
      console.log(alg, txt);
      return txt;
  }
  </code></pre>
  
  <p>Following is my problem.</p>
  
  <pre><code>1. How can i convert my existing hex code into string? I used "hexToString" method (please check the java code)to convert hex into string. However getting weired character (this is also expected but problem is how i can use this transformed key in nodejs.
  2. Can I pass byte array as key to Nodejs? It will make problem easy as I can easily convert my hex key into bytes array and I store my bytes array key in nodejs code.
  3. In my javacode, I have custom padding logic, how can i write same logic in nodejs?
  4. Most importantly, can I achieve same encryption logic in nodejs (similar to java)?
  </code></pre>
  
  <p>Artjom B. helped me to get the insight of nodejs and des3 algorithm. I have edited my post to clarify my exact requirement.</p>
  
  <p>I think my main problem is, how can i feed byte[] as key to nodejs crypto for DES3?</p>
  
  <p>I am kind of stuck. Please help.</p>