AES CBC 相互加解密 Java/PHP/C++

25 8 月

项目中需要用到加密通讯,因为服务器是用php写的,采用了AES CBC 128位加密,由于是内部系统,所以向量iv就默认内置了。当然也可以采用与aeskey一起存储,加解密的时候分离。

下面是代码:

PHP:

$iv = "1234567890123456"; /* 必须16位哦 */

/* 采用128位加密,密钥也必须是16位 */
function aes_encode($sourcestr, $key)
{
    global $iv;
    return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $sourcestr, MCRYPT_MODE_CBC, $iv));
}

function aes_decode($crypttext, $key)
{
    global $iv;
    return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($crypttext), MCRYPT_MODE_CBC, $iv), "\0");
}

Java:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import com.android.util.BASE64.BASE64Decoder;
import com.android.util.BASE64.BASE64Encoder;
/**
 *
 * @author Tom
 */
public class NewAes {
    
    public static String iv = "1234567890123456";
    
    public static String Encrypt(String sSrc, String sKey) throws Exception {  
        if (sKey == null) {  
            System.out.print("Key为空null");  
            return null;  
        }  
        // 判断Key是否为16位  
        if (sKey.length() != 16) {  
            System.out.print("Key长度不是16位");  
            return null;  
        }  
        byte[] raw = sKey.getBytes();  
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");  
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");//"算法/模式/补码方式"  
        IvParameterSpec iv = new IvParameterSpec(NewAes.iv.getBytes());//使用CBC模式,需要一个向量iv,可增加加密算法的强度  
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);  
       
        byte[] srawt = sSrc.getBytes();
        int len = srawt.length;
        /* 计算补0后的长度 */
        while(len % 16 != 0) len ++;
        byte[] sraw = new byte[len];
        /* 在最后补0 */
        for (int i = 0; i < len; ++i) {
            if (i < srawt.length) {
                sraw[i] = srawt[i];
            } else {
                sraw[i] = 0;
            }
        }
        byte[] encrypted = cipher.doFinal(sraw);  
  
        return new BASE64Encoder().encode(encrypted);//此处使用BASE64做转码功能,同时能起到2次加密的作用。  
    }  
  
    // 解密  
    public static String Decrypt(String sSrc, String sKey) throws Exception {  
        try {  
            // 判断Key是否正确  
            if (sKey == null) {  
                System.out.print("Key为空null");  
                return null;  
            }  
            // 判断Key是否为16位  
            if (sKey.length() != 16) {  
                System.out.print("Key长度不是16位");  
                return null;  
            }  
            System.out.println("key is:"+sKey);
            byte[] raw = sKey.getBytes("ASCII");  
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");  
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");  
            IvParameterSpec iv = new IvParameterSpec(NewAes.iv.getBytes());  
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);  
            byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);//先用base64解密  
            try {  
                byte[] original = cipher.doFinal(encrypted1);  
                String originalString = new String(original);  
                return originalString.trim();  
            } catch (Exception e) {  
                System.out.println(e.toString());  
                return null;  
            }  
        } catch (Exception ex) {  
            System.out.println(ex.toString());  
            return null;  
        }  
    } 
}

C++:

char *CryptObject::aes_encode(const char *sourcestr, char *key = "")
{
    if (strcmp(key, "") == 0) key = aeskey;

    int len = strlen(sourcestr);
    unsigned char iv[AES_BLOCK_SIZE+1] = "6543210987654321";  // 注意,iv绝对不能是const的,否则会段错误

    unsigned char * out = (unsigned char *)malloc(1024*1024);
    if (out == NULL) {
        fprintf(stderr, "No Memory!\n");
    }
    AES_KEY aes;
    if(AES_set_encrypt_key((unsigned char*)key, 128, &aes) < 0)
    {
        return NULL;
    }
    /* 计算补0后的长度 */
    int out_len = ((len - 1) / 16 + 1)* 16;
    char * sstr = (char *)malloc(sizeof(char) * out_len + 1);
    /* 补0 */
    memset(sstr, 0, out_len+1);
    strcpy(sstr, sourcestr);
    AES_cbc_encrypt((unsigned char*)sstr, out, out_len, &aes, (unsigned char*)iv, AES_ENCRYPT);
    /* 这里的长度一定要注意,不能用strlen来获取,加密后的字符串中可能会包含\0 */
    char * out2 = base64_encode((char *)out, out_len);
    free(out);
    free(sstr);
    return out2;
}

char *CryptObject::aes_decode(const char *crypttext, char *key = "")
{
    if (strcmp(key, "") == 0) key = aeskey;
    int out_len = 0;
    unsigned char iv[AES_BLOCK_SIZE+1] = "6543210987654321";

    char *in = base64_decode(crypttext, strlen(crypttext), out_len);
    char *out = (char *) malloc(sizeof(char) * out_len + 1);
    memset(out, 0, out_len + 1);
    AES_KEY aes;
    if(AES_set_decrypt_key((unsigned char*)key, 128, &aes) < 0)
    {
        return NULL;
    }

    AES_cbc_encrypt((unsigned char*)in, (unsigned char*)out, out_len, &aes, (unsigned char*)iv, AES_DECRYPT);
    free(in);
    return out;
}

char *CryptObject::base64_encode(const char *data, int data_len)
{
    int prepare = 0;
    int ret_len;
    int temp = 0;
    char *ret = NULL;
    char *f = NULL;
    int tmp = 0;
    char changed[4];
    int i = 0;
    ret_len = data_len / 3;
    temp = data_len % 3;
    if (temp > 0)
    {
	ret_len += 1;
    }
    ret_len = ret_len*4 + 1;
    ret = (char *)malloc(ret_len);

    if ( ret == NULL)
    {
	printf("No enough memory.\n");
	exit(0);
    }
    memset(ret, 0, ret_len);
    f = ret;
    while (tmp < data_len)
    {
	temp = 0;
	prepare = 0;
	memset(changed, '\0', 4);
	while (temp < 3)
	{
	    //printf("tmp = %d\n", tmp);
	    if (tmp >= data_len)
	    {
		break;
	    }
	    prepare = ((prepare << 8) | (data[tmp] & 0xFF));
	    tmp++;
	    temp++;
	}
	prepare = (prepare<<((3-temp)*8));
	//printf("before for : temp = %d, prepare = %d\n", temp, prepare);
	for (i = 0; i < 4 ;i++ )
	{
	    if (temp < i)
	    {
		changed[i] = 0x40;
	    }
	    else
	    {
		changed[i] = (prepare>>((3-i)*6)) & 0x3F;
	    }
	    *f = base[changed[i]];
	    //printf("%.2X", changed[i]);
	    f++;
	}
    }
    *f = '\0';

    return ret;
}

/* out_len 解码后的数据长度 */
char *CryptObject::base64_decode(const char *data, int data_len, int &out_len)
{
    int ret_len = (data_len / 4) * 3;
    int equal_count = 0;
    char *ret = NULL;
    char *f = NULL;
    int tmp = 0;
    int temp = 0;
    char need[3];
    int prepare = 0;
    int i = 0;
    if (*(data + data_len - 1) == '=')
    {
	equal_count += 1;
    }
    if (*(data + data_len - 2) == '=')
    {
	equal_count += 1;
    }
    if (*(data + data_len - 3) == '=')
    {//seems impossible
	equal_count += 1;
    }
    switch (equal_count)
    {
    case 0:
	ret_len += 4;//3 + 1 [1 for NULL]
	break;
    case 1:
	ret_len += 4;//Ceil((6*3)/8)+1
	break;
    case 2:
	ret_len += 3;//Ceil((6*2)/8)+1
	break;
    case 3:
	ret_len += 2;//Ceil((6*1)/8)+1
	break;
    }
    ret = (char *)malloc(ret_len);
    if (ret == NULL)
    {
	printf("No enough memory.\n");
	exit(0);
    }
    memset(ret, 0, ret_len);
    f = ret;
    while (tmp < (data_len - equal_count))
    {
	temp = 0;
	prepare = 0;
	memset(need, 0, 3);
	while (temp < 4)
	{
	    if (tmp >= (data_len - equal_count))
	    {
		break;
	    }
	    prepare = (prepare << 6) | (find_pos(data[tmp]));
	    temp++;
	    tmp++;
	}
	prepare = prepare << ((4-temp) * 6);
	for (i=0; i<3 ;i++ )
	{
	    if (i == temp)
	    {
		break;
	    }
	    *f = (char)((prepare>>((2-i)*8)) & 0xFF);
	    f++;
	}
    }
    *f = '\0';
    out_len = (int)(f - ret);
    if (out_len < 0) out_len = 0;
    return ret;
}

 

23 Replies to “AES CBC 相互加解密 Java/PHP/C++

  1. 涛哥,AES CBC 加解密 Java/PHP/C++ 能发一份源码给我么,228026607@qq.com, 主要是php和c++互通的完整源码,谢谢

  2. 你好,AES CBC 相互加解密 Java/PHP/C++ 能发一份源码给我么,2603529478@qq.com, 主要是php和c++互通的完整源码,,谢谢

  3. 博主,您好,我最近也在搞类似的东西,遇到了一些问题,可以发送一份完整的代码吗?邮箱是:554872164@qq.com。非常感谢!

  4. 你好,AES CBC 相互加解密 Java/PHP/C++ 能发一份源码给我么,852784647@qq.com, 主要是php和c++互通的完整源码,,谢谢

  5. 涛,,我也遇到了这方面的问题,AES CBC 相互加解密 Java/PHP/C++ 能发一份源码给我么,1281635271@qq.com, 主要是php和c++互通,,c++使用的是哪个加密库,谢谢

  6. 涛,你的 C++ AES加密和PHP解密的配套的完整的代码能发一份给我吗? 我的邮箱是 flydish#gmail.com

Comments are closed.