缺少前16个字符 - Java AES CBC加密和golang解密

时间:2017-05-20 01:57:39

标签: java encryption go cryptography

我使用以下代码来加密和解密Java中的数据。加密和解密工作正常。

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.SecureRandom;

public class MainNew {

    public static void main(String[] args) throws Exception{
        String iv = getEncryptionIV();
        System.out.println(" iv = "+iv);

        String encryptedData= encryptWithIVandKey(iv,encryptionKey,"hello world! golang is awesome!");
        System.out.println(encryptedData);
        String decryptedData = decrypt (iv,encryptionKey,encryptedData);
        System.out.println(decryptedData);
    }


    static final String encryptionKey = "rakesh1@n1111112";


    static byte[] doFinal(int encryptMode, SecretKey key, String iv, byte[] bytes) {

        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(encryptMode, key, new IvParameterSpec(DatatypeConverter.parseBase64Binary(iv)));
            byte[] data = cipher.doFinal(bytes);

            return data;

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e);
        }
        return null;

    }



    static SecretKey generateKey(String passphrase) {

        SecretKey key = null;

        try {

            key = new SecretKeySpec(passphrase.getBytes("UTF-8"), "AES");


        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e);
        }

        return key;
    }




    static String getEncryptionIV() {
        SecureRandom random = new SecureRandom();
        byte[] ivBytes = new byte[16];
        random.nextBytes(ivBytes);
        return DatatypeConverter.printBase64Binary(ivBytes);
    }

    static String encryptWithIVandKey( String iv, String passphrase, final String strToEncrypt) {
        String encryptedStr = "";

        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKey key = generateKey(passphrase);
            cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(DatatypeConverter.parseBase64Binary(iv)));

            encryptedStr = DatatypeConverter.printBase64Binary(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e);
        }


        return encryptedStr;
    }

    static String decrypt(String iv, String passphrase, String ciphertext) {
        try {
            SecretKey key = generateKey(passphrase);
            byte[] decrypted = doFinal(Cipher.DECRYPT_MODE, key, iv, DatatypeConverter.parseBase64Binary(ciphertext));
            return new String(decrypted, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e);
        }
        return "";
    }

}

但是如果我使用https://play.golang.org/p/u4fip_ZW6a代码在golang中解密。解密后的值中缺少前16个字符。

1 个答案:

答案 0 :(得分:2)

您在游乐场分享的Go代码:

encryptedStr = DatatypeConverter.printBase64Binary(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));

正如您所看到的,此代码期望encryptWithIVandKey的前16个字节为IV。

但是,在您的Java代码中,您只需:

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKey key = generateKey(passphrase);
        byte[] ivBytes = DatatypeConverter.parseBase64Binary(iv);
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivBytes));
        byte[] encBytes = cipher.doFinal(strToEncrypt.getBytes("UTF-8"));
        // concat iv + encripted bytes
        byte[] concat = new byte[ivBytes.length + encBytes.length];
        System.arraycopy(ivBytes, 0, concat, 0, ivBytes.length);
        System.arraycopy(encBytes, 0, concat, ivBytes.length, encBytes.length);
        encryptedStr = DatatypeConverter.printBase64Binary(concat);

所以你加密字符串,然后你要返回的所有内容(然后在Go程序中使用)。

正如我们所看到的,Go代码正在从密文中删除16个字节,这就是您丢失数据的原因。

我建议您更改Java代码,以便在字符串的开头包含IV,以匹配Go代码所期望的内容。

您可以将Java中的adAz5d5J3PAOuxntOe/9uMJgFHwIcdKobhRSKXwspmnxFlSlF40dtBYf9VSY34fU 方法更改为:

var isInput = false; 

app.post('/webhook', function (req, res) {
    var data = req.body;

      if (data.object === 'page') {

        data.entry.forEach(function(entry) {
          var pageID = entry.id;
          var timeOfEvent = entry.time;
      entry.messaging.forEach(function(event) {
        if (event.message) {
          receivedMessage(event);
        } else if(event.postback){
          receivedPostback(event);
        }
        else {
          console.log("Webhook received unknown event: ", event);
        }
      });
    });

    res.sendStatus(200);
  }
});

function receivedMessage(event) {
  var senderID = event.sender.id;
  var recipientID = event.recipient.id;
  var timeOfMessage = event.timestamp;
  var message = event.message;

  console.log("Received message for user %d and page %d at %d with message:", 
    senderID, recipientID, timeOfMessage);
  console.log(JSON.stringify(message));

  var messageId = message.mid;
  var messageText = message.text;
  var messageAttachments = message.attachments;

  if (messageText) {

    switch (messageText) {

      case 'Vote': 
        delayText(senderID, "Send your message ", 1000); 
        isInput = true; 
        break; 

      default:
        if(isInput){
          token = messageText; 
          sendTextMessage(senderID, "token: " + token)
          isInput = false; 
        } else {
         sendTextMessage(senderID, "isInput: " + isInput)
        }
        break; 
    }
  } 
}

这里的变化是我们在编码之前将IV +加密的字符串连接到Base64。

然后生成的Base64:

{{1}}

如果你在Go代码中尝试使用String,它将产生你期望的输出。