aes加解密 java與go、c語言互通

簡介:java服務端負責解密go和c語言產生得加密數據,這裏採用aes得ECB加密模式

java端得代碼如下:

package com.example.demo;

import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AES {

    public static byte[] encrypt(String key, byte[] origData) throws GeneralSecurityException {

        byte[] keyBytes = getKeyBytes(key);
        byte[] buf = new byte[16];
        System.arraycopy(keyBytes, 0, buf, 0, keyBytes.length > buf.length ? keyBytes.length : buf.length);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(buf, "AES"), new IvParameterSpec(keyBytes));
        return cipher.doFinal(origData);

    }

    public static byte[] decrypt(String key, byte[] crypted) throws GeneralSecurityException {
        byte[] keyBytes = getKeyBytes(key);
        byte[] buf = new byte[16];
        System.arraycopy(keyBytes, 0, buf, 0, keyBytes.length > buf.length ? keyBytes.length : buf.length);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, "AES"), new IvParameterSpec(keyBytes));
        return cipher.doFinal(crypted);
    }

    private static byte[] getKeyBytes(String key) {
        byte[] bytes = key.getBytes();
        return bytes.length == 16 ? bytes : Arrays.copyOf(bytes, 16);
    }

    public static String encrypt(String key, String val) throws GeneralSecurityException {
        byte[] origData = val.getBytes();
        byte[] crypted = encrypt(key, origData);
        return Base64.getEncoder().encodeToString(crypted);
    }

    public static String decrypt(String key, String val) throws GeneralSecurityException {
        byte[] crypted= Base64.getDecoder().decode(val);
        byte[] origData = decrypt(key, crypted);
        return new String(origData);
    }

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        String key = "HelloWorld123456";
        String content = "t0EMsCSB7wwDxlaWnwj23w==";
        System.out.println(decrypt(key, content));
    }

}

C語言客戶端得代碼如下:

/**
  build with shell:
  gcc -Wall aes.c -lcrypto -o aes
**/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>

void encrypt(unsigned char* in, int inl, unsigned char *out, int* len, unsigned char * key){
    unsigned char iv[8];
    EVP_CIPHER_CTX ctx;
    //此init做的僅是將ctx內存 memset爲0  
    EVP_CIPHER_CTX_init(&ctx);

    //cipher  = EVP_aes_128_ecb();  
    //原型爲int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv)   
    //另外對於ecb電子密碼本模式來說,各分組獨立加解密,前後沒有關係,也用不着iv  
    EVP_EncryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, key, iv);  

    *len = 0;
    int outl = 0;
    //這個EVP_EncryptUpdate的實現實際就是將in按照inl的長度去加密,實現會取得該cipher的塊大小(對aes_128來說是16字節)並將block-size的整數倍去加密。
    //如果輸入爲50字節,則此處僅加密48字節,outl也爲48字節。輸入in中的最後兩字節拷貝到ctx->buf緩存起來。  
    //對於inl爲block_size整數倍的情形,且ctx->buf並沒有以前遺留的數據時則直接加解密操作,省去很多後續工作。  
    EVP_EncryptUpdate(&ctx, out+*len, &outl, in+*len, inl);
       *len+=outl;
       //餘下最後n字節。此處進行處理。
       //如果不支持pading,且還有數據的話就出錯,否則,將block_size-待處理字節數個數個字節設置爲此個數的值,如block_size=16,數據長度爲4,則將後面的12字節設置爲16-4=12,補爲一個分組後加密 
       //對於前面爲整分組時,如輸入數據爲16字節,最後再調用此Final時,不過是對16個0進行加密,此密文不用即可,也根本用不着調一下這Final。
       int test = inl>>4;
       if(inl != test<<4){
           EVP_EncryptFinal_ex(&ctx,out+*len,&outl);  
           *len+=outl;
    }
    EVP_CIPHER_CTX_cleanup(&ctx);
}


void decrypt(unsigned char* in, int inl, unsigned char *out, unsigned char *key){
    unsigned char iv[8];
    EVP_CIPHER_CTX ctx;
    //此init做的僅是將ctx內存 memset爲0  
    EVP_CIPHER_CTX_init(&ctx);

    //cipher  = EVP_aes_128_ecb();  
    //原型爲int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv)   
    //另外對於ecb電子密碼本模式來說,各分組獨立加解密,前後沒有關係,也用不着iv  
    EVP_DecryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, key, iv); 
    int len = 0;
    int outl = 0;

    EVP_DecryptUpdate(&ctx, out+len, &outl, in+len, inl);
       len += outl;
        
       EVP_DecryptFinal_ex(&ctx, out+len, &outl);  
       len+=outl;
    out[len]=0;
    EVP_CIPHER_CTX_cleanup(&ctx);
}

#define MAX_BUF_LEN 8192
int main(int argc, char **argv)
{
    unsigned char content[MAX_BUF_LEN];   //待加密得字符串
    unsigned char key[] = "HelloWorld123456";   //加密得key,長度爲固定長度16
    
    unsigned char en[MAX_BUF_LEN],de[MAX_BUF_LEN],base64[MAX_BUF_LEN], base64_out[MAX_BUF_LEN];
    int len; 
    memset(content, 0,MAX_BUF_LEN);
    memset(en, 0, MAX_BUF_LEN);
    memset(de, 0, MAX_BUF_LEN);
    memset(base64, 0,MAX_BUF_LEN);
    memset(base64_out, 0, MAX_BUF_LEN);
    //strcpy(content, "HelloHbnfjkwahgruiep");
    strcpy(content, "我分解機");
    
    printf("%d %s\n", strlen((const char*)content), content);
    encrypt(content,strlen((const char*)content), en, &len, key);
    
    int encode_str_size = EVP_EncodeBlock(base64, en, len);
    printf("%d %s\n", encode_str_size, base64);
    
    int length = EVP_DecodeBlock(base64_out, base64, strlen((const char*)base64));
    //EVP_DecodeBlock內部同樣調用EVP_DecodeInit + EVP_DecodeUpdate + Evp_DecodeFinal實現,但是並未處理尾部的'='字符,因此結果字符串長度總是爲3的倍數
    while(base64[--encode_str_size] == '=') length--;

    
     decrypt(base64_out, length, de, key);
    printf("%d %s\n", strlen((const char*)de), de);
    return 0;
}

go客戶端得代碼如下:

package main

import (
    "crypto/aes"
    "encoding/base64"
    "encoding/hex"
    "log"
    "os"
)

func main() {
    argc := len(os.Args)
    if argc !=3 {
        os.Stdout.WriteString("argc is not 3\n")
            return
    }
    //origData := []byte("Hello World") // 待加密的數據
    origData := []byte(os.Args[2]) // 待加密的數據
    //key := []byte("1234567812345678") // 加密的密鑰
    key := []byte(os.Args[1]) // 加密的密鑰
    log.Println("密鑰", string(key))
    log.Println("原文:", string(origData))

    log.Println("------------------ ECB模式 --------------------")
    encrypted := AesEncryptECB(origData, key)
    log.Println("密文(hex):", hex.EncodeToString(encrypted))
    log.Println("密文(base64):", base64.StdEncoding.EncodeToString(encrypted))
    decrypted := AesDecryptECB(encrypted, key)
    log.Println("解密結果:", string(decrypted))

}


// =================== ECB ======================
func AesEncryptECB(origData []byte, key []byte) (encrypted []byte) {
    cipher, _ := aes.NewCipher(generateKey(key))
    length := (len(origData) + aes.BlockSize) / aes.BlockSize
    plain := make([]byte, length*aes.BlockSize)
    copy(plain, origData)
    pad := byte(len(plain) - len(origData))
    for i := len(origData); i < len(plain); i++ {
        plain[i] = pad
    }
    encrypted = make([]byte, len(plain))
    // 分組分塊加密
    for bs, be := 0, cipher.BlockSize(); bs <= len(origData); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
        cipher.Encrypt(encrypted[bs:be], plain[bs:be])
    }

    return encrypted
}
func AesDecryptECB(encrypted []byte, key []byte) (decrypted []byte) {
    cipher, _ := aes.NewCipher(generateKey(key))
    decrypted = make([]byte, len(encrypted))
    //
    for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
        cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
    }

    trim := 0
    if len(decrypted) > 0 {
        trim = len(decrypted) - int(decrypted[len(decrypted)-1])
    }

    return decrypted[:trim]
}
func generateKey(key []byte) (genKey []byte) {
    genKey = make([]byte, 16)
    copy(genKey, key)
    for i := 16; i < len(key); {
        for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
            genKey[j] ^= key[i]
        }
    }
    return genKey
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章