Java 调用C语言加密

8 篇文章 0 订阅
5 篇文章 0 订阅

前置知识

调用C语言的两种方式:

加密Java工具类

EncryptUtil: 加密工具类

package cn.weezoo.medical.infrastructure.utils;

import cn.weezoo.medical.infrastructure.exception.UnsupportedOperationException;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;

import java.io.*;
import java.nio.charset.Charset;

/**
 * 加密 Util
 *  调用c++动态库。
 *  1、C++实现的方法尽量别以char *作为返回值,使用参数接收输出。
 *  2、C++的char *参数,Java使用byte[]接收。
 *  3、VS2013的编码默认为GB2312
 *  4、IDEA读取文本时会在末尾加换行,注意使用trim修剪一下
 *  5、JAVA中调用原生方法时,传入的字符串记得手动加'\0'
 *  6、JAVA内码为UTF-16,默认外码为UTF-8
 *
 * @author wenei
 * @date 2021-02-27 19:48
 */
public class EncryptUtil {

    private static final String filePath;

    static {
        if (Platform.isWindows()) {
            // windows平台最前面的路径需要去掉一个/
            filePath = ResourceUtil.getSystemPath("lib/encrypt-dll.dll");
        } else if (Platform.isLinux()) {
            filePath = ResourceUtil.getSystemPath("lib/libencrypt.so");
        } else {
            throw new UnsupportedOperationException("未能找到指定动态库进行加载");
        }
    }

    private interface NativeEncryptLibrary extends Library {

        int encrypt(byte[] input, byte[] output, byte[] key);

        int decrypt(byte[] input, byte[] output, byte[] key);

        int get_encrypt_len(byte[] input);

        int get_decrypt_len(byte[] input);
    }

    private static final NativeEncryptLibrary INSTANCE = Native.loadLibrary(filePath, NativeEncryptLibrary.class);

    public static String readToString(String fileName) {
        String encoding = "UTF-8";
        File file = new File(fileName);
        Long filelength = file.length();
        byte[] filecontent = new byte[filelength.intValue()];
        try {
            FileInputStream in = new FileInputStream(file);
            in.read(filecontent);
            in.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            return new String(filecontent, encoding).trim() + "\0";
        } catch (UnsupportedEncodingException e) {
            System.err.println("The OS does not support " + encoding);
            e.printStackTrace();
            return null;
        }
    }

    public static String strTo16(String s) {
        String str = "";
        for (int i = 0; i < s.length(); i++) {
            int ch = (int) s.charAt(i);
            String s4 = Integer.toHexString(ch);
            str = str + s4;
        }
        return str;
    }

    public static String strTo16(byte[] s, int len) {
        String str = "";
        for (int i = 0; i < len; i++) {
            int ch = (int) s[i];
            String s4 = Integer.toHexString(ch);
            str = str + s4;
        }
        return str;
    }

    private static final String key = "ItnvIFgujvHY5rgGxTi3dP89a6siF3pN";

    private static int sum = 0;

    public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
        for (int i = 0; i < 100; i++) {
//            new Thread(() -> {
//                decryptDemo();
//            }).start();
            decryptDemo();
        }
        System.out.println(sum);

        // 测试C语言解密
        String data = readToString(ResourceUtil.getSystemPath("1.txt"));
        byte[] data_txt = data.getBytes("GB2312");
        byte[] cipher_txt = new byte[INSTANCE.get_encrypt_len(data.getBytes("GB2312"))];
        INSTANCE.encrypt(data_txt, cipher_txt, key.getBytes("GB2312"));
        byte[] clear_txt = new byte[INSTANCE.get_decrypt_len(cipher_txt)];
        INSTANCE.decrypt(cipher_txt, clear_txt, key.getBytes("GB2312"));
        System.out.println("解密后:" + new String(clear_txt, "GB2312"));
    }

    private static void decryptDemo() {
        String cipher = readToString(ResourceUtil.getSystemPath("cipher.txt"));
        byte[] cipher_txt = cipher.getBytes(Charset.forName("GB2312"));
//        System.out.println("带解密文本长度:" + cipher.length());
//        System.out.println("待解密文本:");
//        System.out.println(cipher);
//        System.out.println(cipher.getBytes(Charset.forName("GB2312")).length);

        byte[] clear_txt = new byte[INSTANCE.get_decrypt_len(cipher_txt)];
        String clear;
        INSTANCE.decrypt(cipher.getBytes(Charset.forName("GB2312")), clear_txt, key.getBytes(Charset.forName("GB2312")));
        clear = new String(clear_txt, Charset.forName("GB2312"));
//        System.out.println("解密后的文本:" + clear + "###");
        System.out.println("解密后文本长度:" + clear.length());
        System.out.println(clear_txt.length);
        if (clear_txt.length == 13712) {
            sum++;
        }
    }
}

ResourceUtil:资源工具类

package cn.weezoo.medical.infrastructure.utils;

import cn.weezoo.medical.infrastructure.exception.UnsupportedOperationException;
import com.sun.jna.Platform;

import java.net.URL;

/**
 * 资源 Util
 *
 * @author wenei
 * @date 2021-02-27 20:02
 */
public class ResourceUtil {

    public static String getSystemPath(String classResourcePath) {
        URL systemURL = Thread.currentThread().getContextClassLoader().getResource(classResourcePath);
        if (systemURL == null) {
            throw new UnsupportedOperationException(String.format("未找到class路径下的%s资源", classResourcePath));
        }
        if (Platform.isWindows()) {
            // 去掉路径最前面的斜杠
            return systemURL.getPath().substring(1);
        }
        return systemURL.getPath();
    }
}

C语言加密JNA源文件

将下列源文件打成动态库,Java项目中导入即可。

/*********************************************************************
* Filename:   aes.c
* Author:     Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details:    This code is the implementation of the AES algorithm and
the CTR, CBC, and CCM modes of operation it can be used in.
AES is, specified by the NIST in in publication FIPS PUB 197,
availible at:
* http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf .
The CBC and CTR modes of operation are specified by
NIST SP 800-38 A, available at:
* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf .
The CCM mode of operation is specified by NIST SP80-38 C, available at:
* http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
*********************************************************************/

/*************************** HEADER FILES ***************************/
#include "stdafx.h"

/****************************** MACROS ******************************/
// The least significant _BYTE of the word is rotated to the end.
#define KE_ROTWORD(x) (((x) << 8) | ((x) >> 24))

#define TRUE  1
#define FALSE 0

/**************************** DATA TYPES ****************************/
#define AES_128_ROUNDS 10
#define AES_192_ROUNDS 12
#define AES_256_ROUNDS 14

/*********************** FUNCTION DECLARATIONS **********************/
void ccm_prepare_first_ctr_blk(_BYTE counter[], const _BYTE nonce[], int nonce_len, int payload_len_store_size);
void ccm_prepare_first_format_blk(_BYTE buf[], int assoc_len, int payload_len, int payload_len_store_size, int mac_len, const _BYTE nonce[], int nonce_len);
void ccm_format_assoc_data(_BYTE buf[], int *end_of_buf, const _BYTE assoc[], int assoc_len);
void ccm_format_payload_data(_BYTE buf[], int *end_of_buf, const _BYTE payload[], int payload_len);

/**************************** VARIABLES *****************************/
// This is the specified AES SBox. To look up a substitution value, put the first
// nibble in the first index (row) and the second nibble in the second index (column).
static const _BYTE aes_sbox[16][16] = {
		{ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76 },
		{ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0 },
		{ 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15 },
		{ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75 },
		{ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84 },
		{ 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF },
		{ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8 },
		{ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2 },
		{ 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73 },
		{ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB },
		{ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79 },
		{ 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08 },
		{ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A },
		{ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E },
		{ 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF },
		{ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 }
};

static const _BYTE aes_invsbox[16][16] = {
		{ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB },
		{ 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB },
		{ 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E },
		{ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25 },
		{ 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92 },
		{ 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84 },
		{ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06 },
		{ 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B },
		{ 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73 },
		{ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E },
		{ 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B },
		{ 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4 },
		{ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F },
		{ 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF },
		{ 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61 },
		{ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D }
};

// This table stores pre-calculated values for all possible GF(2^8) calculations.This
// table is only used by the (Inv)MixColumns steps.
// USAGE: The second index (column) is the coefficient of multiplication. Only 7 different
// coefficients are used: 0x01, 0x02, 0x03, 0x09, 0x0b, 0x0d, 0x0e, but multiplication by
// 1 is negligible leaving only 6 coefficients. Each column of the table is devoted to one
// of these coefficients, in the ascending order of value, from values 0x00 to 0xFF.
static const _BYTE gf_mul[256][6] = {
		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x02, 0x03, 0x09, 0x0b, 0x0d, 0x0e },
		{ 0x04, 0x06, 0x12, 0x16, 0x1a, 0x1c }, { 0x06, 0x05, 0x1b, 0x1d, 0x17, 0x12 },
		{ 0x08, 0x0c, 0x24, 0x2c, 0x34, 0x38 }, { 0x0a, 0x0f, 0x2d, 0x27, 0x39, 0x36 },
		{ 0x0c, 0x0a, 0x36, 0x3a, 0x2e, 0x24 }, { 0x0e, 0x09, 0x3f, 0x31, 0x23, 0x2a },
		{ 0x10, 0x18, 0x48, 0x58, 0x68, 0x70 }, { 0x12, 0x1b, 0x41, 0x53, 0x65, 0x7e },
		{ 0x14, 0x1e, 0x5a, 0x4e, 0x72, 0x6c }, { 0x16, 0x1d, 0x53, 0x45, 0x7f, 0x62 },
		{ 0x18, 0x14, 0x6c, 0x74, 0x5c, 0x48 }, { 0x1a, 0x17, 0x65, 0x7f, 0x51, 0x46 },
		{ 0x1c, 0x12, 0x7e, 0x62, 0x46, 0x54 }, { 0x1e, 0x11, 0x77, 0x69, 0x4b, 0x5a },
		{ 0x20, 0x30, 0x90, 0xb0, 0xd0, 0xe0 }, { 0x22, 0x33, 0x99, 0xbb, 0xdd, 0xee },
		{ 0x24, 0x36, 0x82, 0xa6, 0xca, 0xfc }, { 0x26, 0x35, 0x8b, 0xad, 0xc7, 0xf2 },
		{ 0x28, 0x3c, 0xb4, 0x9c, 0xe4, 0xd8 }, { 0x2a, 0x3f, 0xbd, 0x97, 0xe9, 0xd6 },
		{ 0x2c, 0x3a, 0xa6, 0x8a, 0xfe, 0xc4 }, { 0x2e, 0x39, 0xaf, 0x81, 0xf3, 0xca },
		{ 0x30, 0x28, 0xd8, 0xe8, 0xb8, 0x90 }, { 0x32, 0x2b, 0xd1, 0xe3, 0xb5, 0x9e },
		{ 0x34, 0x2e, 0xca, 0xfe, 0xa2, 0x8c }, { 0x36, 0x2d, 0xc3, 0xf5, 0xaf, 0x82 },
		{ 0x38, 0x24, 0xfc, 0xc4, 0x8c, 0xa8 }, { 0x3a, 0x27, 0xf5, 0xcf, 0x81, 0xa6 },
		{ 0x3c, 0x22, 0xee, 0xd2, 0x96, 0xb4 }, { 0x3e, 0x21, 0xe7, 0xd9, 0x9b, 0xba },
		{ 0x40, 0x60, 0x3b, 0x7b, 0xbb, 0xdb }, { 0x42, 0x63, 0x32, 0x70, 0xb6, 0xd5 },
		{ 0x44, 0x66, 0x29, 0x6d, 0xa1, 0xc7 }, { 0x46, 0x65, 0x20, 0x66, 0xac, 0xc9 },
		{ 0x48, 0x6c, 0x1f, 0x57, 0x8f, 0xe3 }, { 0x4a, 0x6f, 0x16, 0x5c, 0x82, 0xed },
		{ 0x4c, 0x6a, 0x0d, 0x41, 0x95, 0xff }, { 0x4e, 0x69, 0x04, 0x4a, 0x98, 0xf1 },
		{ 0x50, 0x78, 0x73, 0x23, 0xd3, 0xab }, { 0x52, 0x7b, 0x7a, 0x28, 0xde, 0xa5 },
		{ 0x54, 0x7e, 0x61, 0x35, 0xc9, 0xb7 }, { 0x56, 0x7d, 0x68, 0x3e, 0xc4, 0xb9 },
		{ 0x58, 0x74, 0x57, 0x0f, 0xe7, 0x93 }, { 0x5a, 0x77, 0x5e, 0x04, 0xea, 0x9d },
		{ 0x5c, 0x72, 0x45, 0x19, 0xfd, 0x8f }, { 0x5e, 0x71, 0x4c, 0x12, 0xf0, 0x81 },
		{ 0x60, 0x50, 0xab, 0xcb, 0x6b, 0x3b }, { 0x62, 0x53, 0xa2, 0xc0, 0x66, 0x35 },
		{ 0x64, 0x56, 0xb9, 0xdd, 0x71, 0x27 }, { 0x66, 0x55, 0xb0, 0xd6, 0x7c, 0x29 },
		{ 0x68, 0x5c, 0x8f, 0xe7, 0x5f, 0x03 }, { 0x6a, 0x5f, 0x86, 0xec, 0x52, 0x0d },
		{ 0x6c, 0x5a, 0x9d, 0xf1, 0x45, 0x1f }, { 0x6e, 0x59, 0x94, 0xfa, 0x48, 0x11 },
		{ 0x70, 0x48, 0xe3, 0x93, 0x03, 0x4b }, { 0x72, 0x4b, 0xea, 0x98, 0x0e, 0x45 },
		{ 0x74, 0x4e, 0xf1, 0x85, 0x19, 0x57 }, { 0x76, 0x4d, 0xf8, 0x8e, 0x14, 0x59 },
		{ 0x78, 0x44, 0xc7, 0xbf, 0x37, 0x73 }, { 0x7a, 0x47, 0xce, 0xb4, 0x3a, 0x7d },
		{ 0x7c, 0x42, 0xd5, 0xa9, 0x2d, 0x6f }, { 0x7e, 0x41, 0xdc, 0xa2, 0x20, 0x61 },
		{ 0x80, 0xc0, 0x76, 0xf6, 0x6d, 0xad }, { 0x82, 0xc3, 0x7f, 0xfd, 0x60, 0xa3 },
		{ 0x84, 0xc6, 0x64, 0xe0, 0x77, 0xb1 }, { 0x86, 0xc5, 0x6d, 0xeb, 0x7a, 0xbf },
		{ 0x88, 0xcc, 0x52, 0xda, 0x59, 0x95 }, { 0x8a, 0xcf, 0x5b, 0xd1, 0x54, 0x9b },
		{ 0x8c, 0xca, 0x40, 0xcc, 0x43, 0x89 }, { 0x8e, 0xc9, 0x49, 0xc7, 0x4e, 0x87 },
		{ 0x90, 0xd8, 0x3e, 0xae, 0x05, 0xdd }, { 0x92, 0xdb, 0x37, 0xa5, 0x08, 0xd3 },
		{ 0x94, 0xde, 0x2c, 0xb8, 0x1f, 0xc1 }, { 0x96, 0xdd, 0x25, 0xb3, 0x12, 0xcf },
		{ 0x98, 0xd4, 0x1a, 0x82, 0x31, 0xe5 }, { 0x9a, 0xd7, 0x13, 0x89, 0x3c, 0xeb },
		{ 0x9c, 0xd2, 0x08, 0x94, 0x2b, 0xf9 }, { 0x9e, 0xd1, 0x01, 0x9f, 0x26, 0xf7 },
		{ 0xa0, 0xf0, 0xe6, 0x46, 0xbd, 0x4d }, { 0xa2, 0xf3, 0xef, 0x4d, 0xb0, 0x43 },
		{ 0xa4, 0xf6, 0xf4, 0x50, 0xa7, 0x51 }, { 0xa6, 0xf5, 0xfd, 0x5b, 0xaa, 0x5f },
		{ 0xa8, 0xfc, 0xc2, 0x6a, 0x89, 0x75 }, { 0xaa, 0xff, 0xcb, 0x61, 0x84, 0x7b },
		{ 0xac, 0xfa, 0xd0, 0x7c, 0x93, 0x69 }, { 0xae, 0xf9, 0xd9, 0x77, 0x9e, 0x67 },
		{ 0xb0, 0xe8, 0xae, 0x1e, 0xd5, 0x3d }, { 0xb2, 0xeb, 0xa7, 0x15, 0xd8, 0x33 },
		{ 0xb4, 0xee, 0xbc, 0x08, 0xcf, 0x21 }, { 0xb6, 0xed, 0xb5, 0x03, 0xc2, 0x2f },
		{ 0xb8, 0xe4, 0x8a, 0x32, 0xe1, 0x05 }, { 0xba, 0xe7, 0x83, 0x39, 0xec, 0x0b },
		{ 0xbc, 0xe2, 0x98, 0x24, 0xfb, 0x19 }, { 0xbe, 0xe1, 0x91, 0x2f, 0xf6, 0x17 },
		{ 0xc0, 0xa0, 0x4d, 0x8d, 0xd6, 0x76 }, { 0xc2, 0xa3, 0x44, 0x86, 0xdb, 0x78 },
		{ 0xc4, 0xa6, 0x5f, 0x9b, 0xcc, 0x6a }, { 0xc6, 0xa5, 0x56, 0x90, 0xc1, 0x64 },
		{ 0xc8, 0xac, 0x69, 0xa1, 0xe2, 0x4e }, { 0xca, 0xaf, 0x60, 0xaa, 0xef, 0x40 },
		{ 0xcc, 0xaa, 0x7b, 0xb7, 0xf8, 0x52 }, { 0xce, 0xa9, 0x72, 0xbc, 0xf5, 0x5c },
		{ 0xd0, 0xb8, 0x05, 0xd5, 0xbe, 0x06 }, { 0xd2, 0xbb, 0x0c, 0xde, 0xb3, 0x08 },
		{ 0xd4, 0xbe, 0x17, 0xc3, 0xa4, 0x1a }, { 0xd6, 0xbd, 0x1e, 0xc8, 0xa9, 0x14 },
		{ 0xd8, 0xb4, 0x21, 0xf9, 0x8a, 0x3e }, { 0xda, 0xb7, 0x28, 0xf2, 0x87, 0x30 },
		{ 0xdc, 0xb2, 0x33, 0xef, 0x90, 0x22 }, { 0xde, 0xb1, 0x3a, 0xe4, 0x9d, 0x2c },
		{ 0xe0, 0x90, 0xdd, 0x3d, 0x06, 0x96 }, { 0xe2, 0x93, 0xd4, 0x36, 0x0b, 0x98 },
		{ 0xe4, 0x96, 0xcf, 0x2b, 0x1c, 0x8a }, { 0xe6, 0x95, 0xc6, 0x20, 0x11, 0x84 },
		{ 0xe8, 0x9c, 0xf9, 0x11, 0x32, 0xae }, { 0xea, 0x9f, 0xf0, 0x1a, 0x3f, 0xa0 },
		{ 0xec, 0x9a, 0xeb, 0x07, 0x28, 0xb2 }, { 0xee, 0x99, 0xe2, 0x0c, 0x25, 0xbc },
		{ 0xf0, 0x88, 0x95, 0x65, 0x6e, 0xe6 }, { 0xf2, 0x8b, 0x9c, 0x6e, 0x63, 0xe8 },
		{ 0xf4, 0x8e, 0x87, 0x73, 0x74, 0xfa }, { 0xf6, 0x8d, 0x8e, 0x78, 0x79, 0xf4 },
		{ 0xf8, 0x84, 0xb1, 0x49, 0x5a, 0xde }, { 0xfa, 0x87, 0xb8, 0x42, 0x57, 0xd0 },
		{ 0xfc, 0x82, 0xa3, 0x5f, 0x40, 0xc2 }, { 0xfe, 0x81, 0xaa, 0x54, 0x4d, 0xcc },
		{ 0x1b, 0x9b, 0xec, 0xf7, 0xda, 0x41 }, { 0x19, 0x98, 0xe5, 0xfc, 0xd7, 0x4f },
		{ 0x1f, 0x9d, 0xfe, 0xe1, 0xc0, 0x5d }, { 0x1d, 0x9e, 0xf7, 0xea, 0xcd, 0x53 },
		{ 0x13, 0x97, 0xc8, 0xdb, 0xee, 0x79 }, { 0x11, 0x94, 0xc1, 0xd0, 0xe3, 0x77 },
		{ 0x17, 0x91, 0xda, 0xcd, 0xf4, 0x65 }, { 0x15, 0x92, 0xd3, 0xc6, 0xf9, 0x6b },
		{ 0x0b, 0x83, 0xa4, 0xaf, 0xb2, 0x31 }, { 0x09, 0x80, 0xad, 0xa4, 0xbf, 0x3f },
		{ 0x0f, 0x85, 0xb6, 0xb9, 0xa8, 0x2d }, { 0x0d, 0x86, 0xbf, 0xb2, 0xa5, 0x23 },
		{ 0x03, 0x8f, 0x80, 0x83, 0x86, 0x09 }, { 0x01, 0x8c, 0x89, 0x88, 0x8b, 0x07 },
		{ 0x07, 0x89, 0x92, 0x95, 0x9c, 0x15 }, { 0x05, 0x8a, 0x9b, 0x9e, 0x91, 0x1b },
		{ 0x3b, 0xab, 0x7c, 0x47, 0x0a, 0xa1 }, { 0x39, 0xa8, 0x75, 0x4c, 0x07, 0xaf },
		{ 0x3f, 0xad, 0x6e, 0x51, 0x10, 0xbd }, { 0x3d, 0xae, 0x67, 0x5a, 0x1d, 0xb3 },
		{ 0x33, 0xa7, 0x58, 0x6b, 0x3e, 0x99 }, { 0x31, 0xa4, 0x51, 0x60, 0x33, 0x97 },
		{ 0x37, 0xa1, 0x4a, 0x7d, 0x24, 0x85 }, { 0x35, 0xa2, 0x43, 0x76, 0x29, 0x8b },
		{ 0x2b, 0xb3, 0x34, 0x1f, 0x62, 0xd1 }, { 0x29, 0xb0, 0x3d, 0x14, 0x6f, 0xdf },
		{ 0x2f, 0xb5, 0x26, 0x09, 0x78, 0xcd }, { 0x2d, 0xb6, 0x2f, 0x02, 0x75, 0xc3 },
		{ 0x23, 0xbf, 0x10, 0x33, 0x56, 0xe9 }, { 0x21, 0xbc, 0x19, 0x38, 0x5b, 0xe7 },
		{ 0x27, 0xb9, 0x02, 0x25, 0x4c, 0xf5 }, { 0x25, 0xba, 0x0b, 0x2e, 0x41, 0xfb },
		{ 0x5b, 0xfb, 0xd7, 0x8c, 0x61, 0x9a }, { 0x59, 0xf8, 0xde, 0x87, 0x6c, 0x94 },
		{ 0x5f, 0xfd, 0xc5, 0x9a, 0x7b, 0x86 }, { 0x5d, 0xfe, 0xcc, 0x91, 0x76, 0x88 },
		{ 0x53, 0xf7, 0xf3, 0xa0, 0x55, 0xa2 }, { 0x51, 0xf4, 0xfa, 0xab, 0x58, 0xac },
		{ 0x57, 0xf1, 0xe1, 0xb6, 0x4f, 0xbe }, { 0x55, 0xf2, 0xe8, 0xbd, 0x42, 0xb0 },
		{ 0x4b, 0xe3, 0x9f, 0xd4, 0x09, 0xea }, { 0x49, 0xe0, 0x96, 0xdf, 0x04, 0xe4 },
		{ 0x4f, 0xe5, 0x8d, 0xc2, 0x13, 0xf6 }, { 0x4d, 0xe6, 0x84, 0xc9, 0x1e, 0xf8 },
		{ 0x43, 0xef, 0xbb, 0xf8, 0x3d, 0xd2 }, { 0x41, 0xec, 0xb2, 0xf3, 0x30, 0xdc },
		{ 0x47, 0xe9, 0xa9, 0xee, 0x27, 0xce }, { 0x45, 0xea, 0xa0, 0xe5, 0x2a, 0xc0 },
		{ 0x7b, 0xcb, 0x47, 0x3c, 0xb1, 0x7a }, { 0x79, 0xc8, 0x4e, 0x37, 0xbc, 0x74 },
		{ 0x7f, 0xcd, 0x55, 0x2a, 0xab, 0x66 }, { 0x7d, 0xce, 0x5c, 0x21, 0xa6, 0x68 },
		{ 0x73, 0xc7, 0x63, 0x10, 0x85, 0x42 }, { 0x71, 0xc4, 0x6a, 0x1b, 0x88, 0x4c },
		{ 0x77, 0xc1, 0x71, 0x06, 0x9f, 0x5e }, { 0x75, 0xc2, 0x78, 0x0d, 0x92, 0x50 },
		{ 0x6b, 0xd3, 0x0f, 0x64, 0xd9, 0x0a }, { 0x69, 0xd0, 0x06, 0x6f, 0xd4, 0x04 },
		{ 0x6f, 0xd5, 0x1d, 0x72, 0xc3, 0x16 }, { 0x6d, 0xd6, 0x14, 0x79, 0xce, 0x18 },
		{ 0x63, 0xdf, 0x2b, 0x48, 0xed, 0x32 }, { 0x61, 0xdc, 0x22, 0x43, 0xe0, 0x3c },
		{ 0x67, 0xd9, 0x39, 0x5e, 0xf7, 0x2e }, { 0x65, 0xda, 0x30, 0x55, 0xfa, 0x20 },
		{ 0x9b, 0x5b, 0x9a, 0x01, 0xb7, 0xec }, { 0x99, 0x58, 0x93, 0x0a, 0xba, 0xe2 },
		{ 0x9f, 0x5d, 0x88, 0x17, 0xad, 0xf0 }, { 0x9d, 0x5e, 0x81, 0x1c, 0xa0, 0xfe },
		{ 0x93, 0x57, 0xbe, 0x2d, 0x83, 0xd4 }, { 0x91, 0x54, 0xb7, 0x26, 0x8e, 0xda },
		{ 0x97, 0x51, 0xac, 0x3b, 0x99, 0xc8 }, { 0x95, 0x52, 0xa5, 0x30, 0x94, 0xc6 },
		{ 0x8b, 0x43, 0xd2, 0x59, 0xdf, 0x9c }, { 0x89, 0x40, 0xdb, 0x52, 0xd2, 0x92 },
		{ 0x8f, 0x45, 0xc0, 0x4f, 0xc5, 0x80 }, { 0x8d, 0x46, 0xc9, 0x44, 0xc8, 0x8e },
		{ 0x83, 0x4f, 0xf6, 0x75, 0xeb, 0xa4 }, { 0x81, 0x4c, 0xff, 0x7e, 0xe6, 0xaa },
		{ 0x87, 0x49, 0xe4, 0x63, 0xf1, 0xb8 }, { 0x85, 0x4a, 0xed, 0x68, 0xfc, 0xb6 },
		{ 0xbb, 0x6b, 0x0a, 0xb1, 0x67, 0x0c }, { 0xb9, 0x68, 0x03, 0xba, 0x6a, 0x02 },
		{ 0xbf, 0x6d, 0x18, 0xa7, 0x7d, 0x10 }, { 0xbd, 0x6e, 0x11, 0xac, 0x70, 0x1e },
		{ 0xb3, 0x67, 0x2e, 0x9d, 0x53, 0x34 }, { 0xb1, 0x64, 0x27, 0x96, 0x5e, 0x3a },
		{ 0xb7, 0x61, 0x3c, 0x8b, 0x49, 0x28 }, { 0xb5, 0x62, 0x35, 0x80, 0x44, 0x26 },
		{ 0xab, 0x73, 0x42, 0xe9, 0x0f, 0x7c }, { 0xa9, 0x70, 0x4b, 0xe2, 0x02, 0x72 },
		{ 0xaf, 0x75, 0x50, 0xff, 0x15, 0x60 }, { 0xad, 0x76, 0x59, 0xf4, 0x18, 0x6e },
		{ 0xa3, 0x7f, 0x66, 0xc5, 0x3b, 0x44 }, { 0xa1, 0x7c, 0x6f, 0xce, 0x36, 0x4a },
		{ 0xa7, 0x79, 0x74, 0xd3, 0x21, 0x58 }, { 0xa5, 0x7a, 0x7d, 0xd8, 0x2c, 0x56 },
		{ 0xdb, 0x3b, 0xa1, 0x7a, 0x0c, 0x37 }, { 0xd9, 0x38, 0xa8, 0x71, 0x01, 0x39 },
		{ 0xdf, 0x3d, 0xb3, 0x6c, 0x16, 0x2b }, { 0xdd, 0x3e, 0xba, 0x67, 0x1b, 0x25 },
		{ 0xd3, 0x37, 0x85, 0x56, 0x38, 0x0f }, { 0xd1, 0x34, 0x8c, 0x5d, 0x35, 0x01 },
		{ 0xd7, 0x31, 0x97, 0x40, 0x22, 0x13 }, { 0xd5, 0x32, 0x9e, 0x4b, 0x2f, 0x1d },
		{ 0xcb, 0x23, 0xe9, 0x22, 0x64, 0x47 }, { 0xc9, 0x20, 0xe0, 0x29, 0x69, 0x49 },
		{ 0xcf, 0x25, 0xfb, 0x34, 0x7e, 0x5b }, { 0xcd, 0x26, 0xf2, 0x3f, 0x73, 0x55 },
		{ 0xc3, 0x2f, 0xcd, 0x0e, 0x50, 0x7f }, { 0xc1, 0x2c, 0xc4, 0x05, 0x5d, 0x71 },
		{ 0xc7, 0x29, 0xdf, 0x18, 0x4a, 0x63 }, { 0xc5, 0x2a, 0xd6, 0x13, 0x47, 0x6d },
		{ 0xfb, 0x0b, 0x31, 0xca, 0xdc, 0xd7 }, { 0xf9, 0x08, 0x38, 0xc1, 0xd1, 0xd9 },
		{ 0xff, 0x0d, 0x23, 0xdc, 0xc6, 0xcb }, { 0xfd, 0x0e, 0x2a, 0xd7, 0xcb, 0xc5 },
		{ 0xf3, 0x07, 0x15, 0xe6, 0xe8, 0xef }, { 0xf1, 0x04, 0x1c, 0xed, 0xe5, 0xe1 },
		{ 0xf7, 0x01, 0x07, 0xf0, 0xf2, 0xf3 }, { 0xf5, 0x02, 0x0e, 0xfb, 0xff, 0xfd },
		{ 0xeb, 0x13, 0x79, 0x92, 0xb4, 0xa7 }, { 0xe9, 0x10, 0x70, 0x99, 0xb9, 0xa9 },
		{ 0xef, 0x15, 0x6b, 0x84, 0xae, 0xbb }, { 0xed, 0x16, 0x62, 0x8f, 0xa3, 0xb5 },
		{ 0xe3, 0x1f, 0x5d, 0xbe, 0x80, 0x9f }, { 0xe1, 0x1c, 0x54, 0xb5, 0x8d, 0x91 },
		{ 0xe7, 0x19, 0x4f, 0xa8, 0x9a, 0x83 }, { 0xe5, 0x1a, 0x46, 0xa3, 0x97, 0x8d }
};

/*********************** FUNCTION DEFINITIONS ***********************/
// XORs the in and out buffers, storing the result in out. Length is in _BYTEs.
void xor_buf(const _BYTE in[], _BYTE out[], size_t len)
{
	size_t idx;

	for (idx = 0; idx < len; idx++)
		out[idx] ^= in[idx];
}


/*******************
* AES
*******************/
/
// KEY EXPANSION
/

// Substitutes a word using the AES S-Box.
_WORD SubWord(_WORD word)
{
	unsigned int result;

	result = (int)aes_sbox[(word >> 4) & 0x0000000F][word & 0x0000000F];
	result += (int)aes_sbox[(word >> 12) & 0x0000000F][(word >> 8) & 0x0000000F] << 8;
	result += (int)aes_sbox[(word >> 20) & 0x0000000F][(word >> 16) & 0x0000000F] << 16;
	result += (int)aes_sbox[(word >> 28) & 0x0000000F][(word >> 24) & 0x0000000F] << 24;
	return(result);
}

// Performs the action of generating the keys that will be used in every round of
// encryption. "key" is the user-supplied input key, "w" is the output key schedule,
// "keysize" is the length in bits of "key", must be 128, 192, or 256.
void aes_key_setup(const _BYTE key[], _WORD w[], int keysize)
{
	int Nb = 4, Nr, Nk, idx;
	_WORD temp, Rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000,
		0x40000000, 0x80000000, 0x1b000000, 0x36000000, 0x6c000000, 0xd8000000,
		0xab000000, 0x4d000000, 0x9a000000 };

	switch (keysize) {
	case 128: Nr = 10; Nk = 4; break;
	case 192: Nr = 12; Nk = 6; break;
	case 256: Nr = 14; Nk = 8; break;
	default: return;
	}

	for (idx = 0; idx < Nk; ++idx) {
		w[idx] = ((key[4 * idx]) << 24) | ((key[4 * idx + 1]) << 16) |
			((key[4 * idx + 2]) << 8) | ((key[4 * idx + 3]));
	}

	for (idx = Nk; idx < Nb * (Nr + 1); ++idx) {
		temp = w[idx - 1];
		if ((idx % Nk) == 0)
			temp = SubWord(KE_ROTWORD(temp)) ^ Rcon[(idx - 1) / Nk];
		else if (Nk > 6 && (idx % Nk) == 4)
			temp = SubWord(temp);
		w[idx] = w[idx - Nk] ^ temp;
	}
}

/
// ADD ROUND KEY
/

// Performs the AddRoundKey step. Each round has its own pre-generated 16-_BYTE key in the
// form of 4 integers (the "w" array). Each integer is XOR'd by one column of the state.
// Also performs the job of InvAddRoundKey(); since the function is a simple XOR process,
// it is its own inverse.
void AddRoundKey(_BYTE state[][4], const _WORD w[])
{
	_BYTE subkey[4];

	// memcpy(subkey,&w[idx],4); // Not accurate for big endian machines
	// Subkey 1
	subkey[0] = w[0] >> 24;
	subkey[1] = w[0] >> 16;
	subkey[2] = w[0] >> 8;
	subkey[3] = w[0];
	state[0][0] ^= subkey[0];
	state[1][0] ^= subkey[1];
	state[2][0] ^= subkey[2];
	state[3][0] ^= subkey[3];
	// Subkey 2
	subkey[0] = w[1] >> 24;
	subkey[1] = w[1] >> 16;
	subkey[2] = w[1] >> 8;
	subkey[3] = w[1];
	state[0][1] ^= subkey[0];
	state[1][1] ^= subkey[1];
	state[2][1] ^= subkey[2];
	state[3][1] ^= subkey[3];
	// Subkey 3
	subkey[0] = w[2] >> 24;
	subkey[1] = w[2] >> 16;
	subkey[2] = w[2] >> 8;
	subkey[3] = w[2];
	state[0][2] ^= subkey[0];
	state[1][2] ^= subkey[1];
	state[2][2] ^= subkey[2];
	state[3][2] ^= subkey[3];
	// Subkey 4
	subkey[0] = w[3] >> 24;
	subkey[1] = w[3] >> 16;
	subkey[2] = w[3] >> 8;
	subkey[3] = w[3];
	state[0][3] ^= subkey[0];
	state[1][3] ^= subkey[1];
	state[2][3] ^= subkey[2];
	state[3][3] ^= subkey[3];
}

/
// (Inv)SubBytes
/

// Performs the SubBytes step. All _BYTEs in the state are substituted with a
// pre-calculated value from a lookup table.
void SubBytes(_BYTE state[][4])
{
	state[0][0] = aes_sbox[state[0][0] >> 4][state[0][0] & 0x0F];
	state[0][1] = aes_sbox[state[0][1] >> 4][state[0][1] & 0x0F];
	state[0][2] = aes_sbox[state[0][2] >> 4][state[0][2] & 0x0F];
	state[0][3] = aes_sbox[state[0][3] >> 4][state[0][3] & 0x0F];
	state[1][0] = aes_sbox[state[1][0] >> 4][state[1][0] & 0x0F];
	state[1][1] = aes_sbox[state[1][1] >> 4][state[1][1] & 0x0F];
	state[1][2] = aes_sbox[state[1][2] >> 4][state[1][2] & 0x0F];
	state[1][3] = aes_sbox[state[1][3] >> 4][state[1][3] & 0x0F];
	state[2][0] = aes_sbox[state[2][0] >> 4][state[2][0] & 0x0F];
	state[2][1] = aes_sbox[state[2][1] >> 4][state[2][1] & 0x0F];
	state[2][2] = aes_sbox[state[2][2] >> 4][state[2][2] & 0x0F];
	state[2][3] = aes_sbox[state[2][3] >> 4][state[2][3] & 0x0F];
	state[3][0] = aes_sbox[state[3][0] >> 4][state[3][0] & 0x0F];
	state[3][1] = aes_sbox[state[3][1] >> 4][state[3][1] & 0x0F];
	state[3][2] = aes_sbox[state[3][2] >> 4][state[3][2] & 0x0F];
	state[3][3] = aes_sbox[state[3][3] >> 4][state[3][3] & 0x0F];
}

void InvSubBytes(_BYTE state[][4])
{
	state[0][0] = aes_invsbox[state[0][0] >> 4][state[0][0] & 0x0F];
	state[0][1] = aes_invsbox[state[0][1] >> 4][state[0][1] & 0x0F];
	state[0][2] = aes_invsbox[state[0][2] >> 4][state[0][2] & 0x0F];
	state[0][3] = aes_invsbox[state[0][3] >> 4][state[0][3] & 0x0F];
	state[1][0] = aes_invsbox[state[1][0] >> 4][state[1][0] & 0x0F];
	state[1][1] = aes_invsbox[state[1][1] >> 4][state[1][1] & 0x0F];
	state[1][2] = aes_invsbox[state[1][2] >> 4][state[1][2] & 0x0F];
	state[1][3] = aes_invsbox[state[1][3] >> 4][state[1][3] & 0x0F];
	state[2][0] = aes_invsbox[state[2][0] >> 4][state[2][0] & 0x0F];
	state[2][1] = aes_invsbox[state[2][1] >> 4][state[2][1] & 0x0F];
	state[2][2] = aes_invsbox[state[2][2] >> 4][state[2][2] & 0x0F];
	state[2][3] = aes_invsbox[state[2][3] >> 4][state[2][3] & 0x0F];
	state[3][0] = aes_invsbox[state[3][0] >> 4][state[3][0] & 0x0F];
	state[3][1] = aes_invsbox[state[3][1] >> 4][state[3][1] & 0x0F];
	state[3][2] = aes_invsbox[state[3][2] >> 4][state[3][2] & 0x0F];
	state[3][3] = aes_invsbox[state[3][3] >> 4][state[3][3] & 0x0F];
}

/
// (Inv)ShiftRows
/

// Performs the ShiftRows step. All rows are shifted cylindrically to the left.
void ShiftRows(_BYTE state[][4])
{
	int t;

	// Shift left by 1
	t = state[1][0];
	state[1][0] = state[1][1];
	state[1][1] = state[1][2];
	state[1][2] = state[1][3];
	state[1][3] = t;
	// Shift left by 2
	t = state[2][0];
	state[2][0] = state[2][2];
	state[2][2] = t;
	t = state[2][1];
	state[2][1] = state[2][3];
	state[2][3] = t;
	// Shift left by 3
	t = state[3][0];
	state[3][0] = state[3][3];
	state[3][3] = state[3][2];
	state[3][2] = state[3][1];
	state[3][1] = t;
}

// All rows are shifted cylindrically to the right.
void InvShiftRows(_BYTE state[][4])
{
	int t;

	// Shift right by 1
	t = state[1][3];
	state[1][3] = state[1][2];
	state[1][2] = state[1][1];
	state[1][1] = state[1][0];
	state[1][0] = t;
	// Shift right by 2
	t = state[2][3];
	state[2][3] = state[2][1];
	state[2][1] = t;
	t = state[2][2];
	state[2][2] = state[2][0];
	state[2][0] = t;
	// Shift right by 3
	t = state[3][3];
	state[3][3] = state[3][0];
	state[3][0] = state[3][1];
	state[3][1] = state[3][2];
	state[3][2] = t;
}

/
// (Inv)MixColumns
/

// Performs the MixColums step. The state is multiplied by itself using matrix
// multiplication in a Galios Field 2^8. All multiplication is pre-computed in a table.
// Addition is equivilent to XOR. (Must always make a copy of the column as the original
// values will be destoyed.)
void MixColumns(_BYTE state[][4])
{
	_BYTE col[4];

	// Column 1
	col[0] = state[0][0];
	col[1] = state[1][0];
	col[2] = state[2][0];
	col[3] = state[3][0];
	state[0][0] = gf_mul[col[0]][0];
	state[0][0] ^= gf_mul[col[1]][1];
	state[0][0] ^= col[2];
	state[0][0] ^= col[3];
	state[1][0] = col[0];
	state[1][0] ^= gf_mul[col[1]][0];
	state[1][0] ^= gf_mul[col[2]][1];
	state[1][0] ^= col[3];
	state[2][0] = col[0];
	state[2][0] ^= col[1];
	state[2][0] ^= gf_mul[col[2]][0];
	state[2][0] ^= gf_mul[col[3]][1];
	state[3][0] = gf_mul[col[0]][1];
	state[3][0] ^= col[1];
	state[3][0] ^= col[2];
	state[3][0] ^= gf_mul[col[3]][0];
	// Column 2
	col[0] = state[0][1];
	col[1] = state[1][1];
	col[2] = state[2][1];
	col[3] = state[3][1];
	state[0][1] = gf_mul[col[0]][0];
	state[0][1] ^= gf_mul[col[1]][1];
	state[0][1] ^= col[2];
	state[0][1] ^= col[3];
	state[1][1] = col[0];
	state[1][1] ^= gf_mul[col[1]][0];
	state[1][1] ^= gf_mul[col[2]][1];
	state[1][1] ^= col[3];
	state[2][1] = col[0];
	state[2][1] ^= col[1];
	state[2][1] ^= gf_mul[col[2]][0];
	state[2][1] ^= gf_mul[col[3]][1];
	state[3][1] = gf_mul[col[0]][1];
	state[3][1] ^= col[1];
	state[3][1] ^= col[2];
	state[3][1] ^= gf_mul[col[3]][0];
	// Column 3
	col[0] = state[0][2];
	col[1] = state[1][2];
	col[2] = state[2][2];
	col[3] = state[3][2];
	state[0][2] = gf_mul[col[0]][0];
	state[0][2] ^= gf_mul[col[1]][1];
	state[0][2] ^= col[2];
	state[0][2] ^= col[3];
	state[1][2] = col[0];
	state[1][2] ^= gf_mul[col[1]][0];
	state[1][2] ^= gf_mul[col[2]][1];
	state[1][2] ^= col[3];
	state[2][2] = col[0];
	state[2][2] ^= col[1];
	state[2][2] ^= gf_mul[col[2]][0];
	state[2][2] ^= gf_mul[col[3]][1];
	state[3][2] = gf_mul[col[0]][1];
	state[3][2] ^= col[1];
	state[3][2] ^= col[2];
	state[3][2] ^= gf_mul[col[3]][0];
	// Column 4
	col[0] = state[0][3];
	col[1] = state[1][3];
	col[2] = state[2][3];
	col[3] = state[3][3];
	state[0][3] = gf_mul[col[0]][0];
	state[0][3] ^= gf_mul[col[1]][1];
	state[0][3] ^= col[2];
	state[0][3] ^= col[3];
	state[1][3] = col[0];
	state[1][3] ^= gf_mul[col[1]][0];
	state[1][3] ^= gf_mul[col[2]][1];
	state[1][3] ^= col[3];
	state[2][3] = col[0];
	state[2][3] ^= col[1];
	state[2][3] ^= gf_mul[col[2]][0];
	state[2][3] ^= gf_mul[col[3]][1];
	state[3][3] = gf_mul[col[0]][1];
	state[3][3] ^= col[1];
	state[3][3] ^= col[2];
	state[3][3] ^= gf_mul[col[3]][0];
}

void InvMixColumns(_BYTE state[][4])
{
	_BYTE col[4];

	// Column 1
	col[0] = state[0][0];
	col[1] = state[1][0];
	col[2] = state[2][0];
	col[3] = state[3][0];
	state[0][0] = gf_mul[col[0]][5];
	state[0][0] ^= gf_mul[col[1]][3];
	state[0][0] ^= gf_mul[col[2]][4];
	state[0][0] ^= gf_mul[col[3]][2];
	state[1][0] = gf_mul[col[0]][2];
	state[1][0] ^= gf_mul[col[1]][5];
	state[1][0] ^= gf_mul[col[2]][3];
	state[1][0] ^= gf_mul[col[3]][4];
	state[2][0] = gf_mul[col[0]][4];
	state[2][0] ^= gf_mul[col[1]][2];
	state[2][0] ^= gf_mul[col[2]][5];
	state[2][0] ^= gf_mul[col[3]][3];
	state[3][0] = gf_mul[col[0]][3];
	state[3][0] ^= gf_mul[col[1]][4];
	state[3][0] ^= gf_mul[col[2]][2];
	state[3][0] ^= gf_mul[col[3]][5];
	// Column 2
	col[0] = state[0][1];
	col[1] = state[1][1];
	col[2] = state[2][1];
	col[3] = state[3][1];
	state[0][1] = gf_mul[col[0]][5];
	state[0][1] ^= gf_mul[col[1]][3];
	state[0][1] ^= gf_mul[col[2]][4];
	state[0][1] ^= gf_mul[col[3]][2];
	state[1][1] = gf_mul[col[0]][2];
	state[1][1] ^= gf_mul[col[1]][5];
	state[1][1] ^= gf_mul[col[2]][3];
	state[1][1] ^= gf_mul[col[3]][4];
	state[2][1] = gf_mul[col[0]][4];
	state[2][1] ^= gf_mul[col[1]][2];
	state[2][1] ^= gf_mul[col[2]][5];
	state[2][1] ^= gf_mul[col[3]][3];
	state[3][1] = gf_mul[col[0]][3];
	state[3][1] ^= gf_mul[col[1]][4];
	state[3][1] ^= gf_mul[col[2]][2];
	state[3][1] ^= gf_mul[col[3]][5];
	// Column 3
	col[0] = state[0][2];
	col[1] = state[1][2];
	col[2] = state[2][2];
	col[3] = state[3][2];
	state[0][2] = gf_mul[col[0]][5];
	state[0][2] ^= gf_mul[col[1]][3];
	state[0][2] ^= gf_mul[col[2]][4];
	state[0][2] ^= gf_mul[col[3]][2];
	state[1][2] = gf_mul[col[0]][2];
	state[1][2] ^= gf_mul[col[1]][5];
	state[1][2] ^= gf_mul[col[2]][3];
	state[1][2] ^= gf_mul[col[3]][4];
	state[2][2] = gf_mul[col[0]][4];
	state[2][2] ^= gf_mul[col[1]][2];
	state[2][2] ^= gf_mul[col[2]][5];
	state[2][2] ^= gf_mul[col[3]][3];
	state[3][2] = gf_mul[col[0]][3];
	state[3][2] ^= gf_mul[col[1]][4];
	state[3][2] ^= gf_mul[col[2]][2];
	state[3][2] ^= gf_mul[col[3]][5];
	// Column 4
	col[0] = state[0][3];
	col[1] = state[1][3];
	col[2] = state[2][3];
	col[3] = state[3][3];
	state[0][3] = gf_mul[col[0]][5];
	state[0][3] ^= gf_mul[col[1]][3];
	state[0][3] ^= gf_mul[col[2]][4];
	state[0][3] ^= gf_mul[col[3]][2];
	state[1][3] = gf_mul[col[0]][2];
	state[1][3] ^= gf_mul[col[1]][5];
	state[1][3] ^= gf_mul[col[2]][3];
	state[1][3] ^= gf_mul[col[3]][4];
	state[2][3] = gf_mul[col[0]][4];
	state[2][3] ^= gf_mul[col[1]][2];
	state[2][3] ^= gf_mul[col[2]][5];
	state[2][3] ^= gf_mul[col[3]][3];
	state[3][3] = gf_mul[col[0]][3];
	state[3][3] ^= gf_mul[col[1]][4];
	state[3][3] ^= gf_mul[col[2]][2];
	state[3][3] ^= gf_mul[col[3]][5];
}

/
// (En/De)Crypt
/
void print_state(_BYTE state[][4])
{
	printf("state:\n");
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 4; j++) {
			printf("%02x ", state[i][j]);
		}
		printf("\n");
	}
	printf("\n");

}

void aes_encrypt(const _BYTE in[], _BYTE out[], const _WORD key[], int keysize)
{
	_BYTE state[4][4];

	// Copy input array (should be 16 bytes long) to a matrix (sequential bytes are ordered
	// by row, not col) called "state" for processing.
	// *** Implementation note: The official AES documentation references the state by
	// column, then row. Accessing an element in C requires row then column. Thus, all state
	// references in AES must have the column and row indexes reversed for C implementation.
	state[0][0] = in[0];
	state[1][0] = in[1];
	state[2][0] = in[2];
	state[3][0] = in[3];
	state[0][1] = in[4];
	state[1][1] = in[5];
	state[2][1] = in[6];
	state[3][1] = in[7];
	state[0][2] = in[8];
	state[1][2] = in[9];
	state[2][2] = in[10];
	state[3][2] = in[11];
	state[0][3] = in[12];
	state[1][3] = in[13];
	state[2][3] = in[14];
	state[3][3] = in[15];

	// Perform the necessary number of rounds. The round key is added first.
	// The last round does not perform the MixColumns step.
	AddRoundKey(state, &key[0]);
	SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[4]);
	SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[8]);
	SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[12]);
	SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[16]);
	SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[20]);
	SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[24]);
	SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[28]);
	SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[32]);
	SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[36]);
	if (keysize != 128) {
		SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[40]);
		SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[44]);
		if (keysize != 192) {
			SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[48]);
			SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, &key[52]);
			SubBytes(state); ShiftRows(state); AddRoundKey(state, &key[56]);
		}
		else {
			SubBytes(state); ShiftRows(state); AddRoundKey(state, &key[48]);
		}
	}
	else {
		SubBytes(state); ShiftRows(state); AddRoundKey(state, &key[40]);
	}

	// Copy the state to the output array.
	out[0] = state[0][0];
	out[1] = state[1][0];
	out[2] = state[2][0];
	out[3] = state[3][0];
	out[4] = state[0][1];
	out[5] = state[1][1];
	out[6] = state[2][1];
	out[7] = state[3][1];
	out[8] = state[0][2];
	out[9] = state[1][2];
	out[10] = state[2][2];
	out[11] = state[3][2];
	out[12] = state[0][3];
	out[13] = state[1][3];
	out[14] = state[2][3];
	out[15] = state[3][3];
}

void aes_decrypt(const _BYTE in[], _BYTE out[], const _WORD key[], int keysize)
{
	_BYTE state[4][4];

	// Copy the input to the state.
	state[0][0] = in[0];
	state[1][0] = in[1];
	state[2][0] = in[2];
	state[3][0] = in[3];
	state[0][1] = in[4];
	state[1][1] = in[5];
	state[2][1] = in[6];
	state[3][1] = in[7];
	state[0][2] = in[8];
	state[1][2] = in[9];
	state[2][2] = in[10];
	state[3][2] = in[11];
	state[0][3] = in[12];
	state[1][3] = in[13];
	state[2][3] = in[14];
	state[3][3] = in[15];

	// Perform the necessary number of rounds. The round key is added first.
	// The last round does not perform the MixColumns step.
	if (keysize > 128) {
		if (keysize > 192) {
			AddRoundKey(state, &key[56]);
			InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[52]); InvMixColumns(state);
			InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[48]); InvMixColumns(state);
		}
		else {
			AddRoundKey(state, &key[48]);
		}
		InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[44]); InvMixColumns(state);
		InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[40]); InvMixColumns(state);
	}
	else {
		AddRoundKey(state, &key[40]);
	}
	InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[36]); InvMixColumns(state);
	InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[32]); InvMixColumns(state);
	InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[28]); InvMixColumns(state);
	InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[24]); InvMixColumns(state);
	InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[20]); InvMixColumns(state);
	InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[16]); InvMixColumns(state);
	InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[12]); InvMixColumns(state);
	InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[8]); InvMixColumns(state);
	InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[4]); InvMixColumns(state);
	InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, &key[0]);

	// Copy the state to the output array.
	out[0] = state[0][0];
	out[1] = state[1][0];
	out[2] = state[2][0];
	out[3] = state[3][0];
	out[4] = state[0][1];
	out[5] = state[1][1];
	out[6] = state[2][1];
	out[7] = state[3][1];
	out[8] = state[0][2];
	out[9] = state[1][2];
	out[10] = state[2][2];
	out[11] = state[3][2];
	out[12] = state[0][3];
	out[13] = state[1][3];
	out[14] = state[2][3];
	out[15] = state[3][3];
}

void print_aes_cipher(char *cipher, int len)
{
	for (int i = 0; i < len; i++) {
		printf("%02x", cipher[i]);
	}
	printf("\n");
}

/*******************
* AES - CBC
*******************/
int aes_encrypt_cbc(const _BYTE in[], size_t in_len, _BYTE out[], const _WORD key[], int keysize, const _BYTE iv[])
{

	_BYTE buf_in[AES_BLOCK_SIZE], buf_out[AES_BLOCK_SIZE], iv_buf[AES_BLOCK_SIZE];
	int blocks, idx;

	if (in_len % AES_BLOCK_SIZE != 0)
		return(FALSE);

	blocks = in_len / AES_BLOCK_SIZE;

	memcpy(iv_buf, iv, AES_BLOCK_SIZE);

	for (idx = 0; idx < blocks; idx++) {
		memcpy(buf_in, in, AES_BLOCK_SIZE);
		xor_buf(iv_buf, buf_in, AES_BLOCK_SIZE);
		aes_encrypt(buf_in, buf_out, key, keysize);
		memcpy(out, buf_out, AES_BLOCK_SIZE);
		memcpy(iv_buf, buf_out, AES_BLOCK_SIZE);
	}

	return(TRUE);
}

int aes_encrypt_cbc_mac(const _BYTE in[], size_t in_len, _BYTE out[], const _WORD key[], int keysize, const _BYTE iv[])
{
	_BYTE buf_in[AES_BLOCK_SIZE], buf_out[AES_BLOCK_SIZE], iv_buf[AES_BLOCK_SIZE];
	int blocks, idx;

	if (in_len % AES_BLOCK_SIZE != 0)
		return(FALSE);

	blocks = in_len / AES_BLOCK_SIZE;

	memcpy(iv_buf, iv, AES_BLOCK_SIZE);

	for (idx = 0; idx < blocks; idx++) {
		memcpy(buf_in, &in[idx * AES_BLOCK_SIZE], AES_BLOCK_SIZE);
		xor_buf(iv_buf, buf_in, AES_BLOCK_SIZE);
		aes_encrypt(buf_in, buf_out, key, keysize);
		memcpy(iv_buf, buf_out, AES_BLOCK_SIZE);
		// Do not output all encrypted blocks.
	}

	memcpy(out, buf_out, AES_BLOCK_SIZE);   // Only output the last block.

	return(TRUE);
}

int aes_decrypt_cbc(const _BYTE in[], size_t in_len, _BYTE out[], const _WORD key[], int keysize, const _BYTE iv[])
{
	_BYTE buf_in[AES_BLOCK_SIZE], buf_out[AES_BLOCK_SIZE], iv_buf[AES_BLOCK_SIZE];
	int blocks, idx;

	if (in_len % AES_BLOCK_SIZE != 0)
		return(FALSE);

	blocks = in_len / AES_BLOCK_SIZE;

	memcpy(iv_buf, iv, AES_BLOCK_SIZE);

	for (idx = 0; idx < blocks; idx++) {
		memcpy(buf_in, &in[idx * AES_BLOCK_SIZE], AES_BLOCK_SIZE);
		aes_decrypt(buf_in, buf_out, key, keysize);
		xor_buf(iv_buf, buf_out, AES_BLOCK_SIZE);
		memcpy(&out[idx * AES_BLOCK_SIZE], buf_out, AES_BLOCK_SIZE);
		memcpy(iv_buf, buf_in, AES_BLOCK_SIZE);
	}

	return(TRUE);
}

/*******************
* AES - CTR
*******************/
void increment_iv(_BYTE iv[], int counter_size)
{
	int idx;

	// Use counter_size _BYTEs at the end of the IV as the big-endian integer to increment.
	for (idx = AES_BLOCK_SIZE - 1; idx >= AES_BLOCK_SIZE - counter_size; idx--) {
		iv[idx]++;
		if (iv[idx] != 0 || idx == AES_BLOCK_SIZE - counter_size)
			break;
	}
}

// Performs the encryption in-place, the input and output buffers may be the same.
// Input may be an arbitrary length (in _BYTEs).
void aes_encrypt_ctr(const _BYTE in[], size_t in_len, _BYTE out[], const _WORD key[], int keysize, const _BYTE iv[])
{
	size_t idx = 0, last_block_length;
	_BYTE iv_buf[AES_BLOCK_SIZE], out_buf[AES_BLOCK_SIZE];

	if (in != out)
		memcpy(out, in, in_len);

	memcpy(iv_buf, iv, AES_BLOCK_SIZE);
	last_block_length = in_len - AES_BLOCK_SIZE;

	if (in_len > AES_BLOCK_SIZE) {
		for (idx = 0; idx < last_block_length; idx += AES_BLOCK_SIZE) {
			aes_encrypt(iv_buf, out_buf, key, keysize);
			xor_buf(out_buf, &out[idx], AES_BLOCK_SIZE);
			increment_iv(iv_buf, AES_BLOCK_SIZE);
		}
	}

	aes_encrypt(iv_buf, out_buf, key, keysize);
	xor_buf(out_buf, &out[idx], in_len - idx);   // Use the Most Significant _BYTEs.
}

void aes_decrypt_ctr(const _BYTE in[], size_t in_len, _BYTE out[], const _WORD key[], int keysize, const _BYTE iv[])
{
	// CTR encryption is its own inverse function.
	aes_encrypt_ctr(in, in_len, out, key, keysize, iv);
}


// Creates the first counter block. First _BYTE is flags, then the nonce, then the incremented part.
void ccm_prepare_first_ctr_blk(_BYTE counter[], const _BYTE nonce[], int nonce_len, int payload_len_store_size)
{
	memset(counter, 0, AES_BLOCK_SIZE);
	counter[0] = (payload_len_store_size - 1) & 0x07;
	memcpy(&counter[1], nonce, nonce_len);
}

void ccm_prepare_first_format_blk(_BYTE buf[], int assoc_len, int payload_len, int payload_len_store_size, int mac_len, const _BYTE nonce[], int nonce_len)
{
	// Set the flags for the first _BYTE of the first block.
	buf[0] = ((((mac_len - 2) / 2) & 0x07) << 3) | ((payload_len_store_size - 1) & 0x07);
	if (assoc_len > 0)
		buf[0] += 0x40;
	// Format the rest of the first block, storing the nonce and the size of the payload.
	memcpy(&buf[1], nonce, nonce_len);
	memset(&buf[1 + nonce_len], 0, AES_BLOCK_SIZE - 1 - nonce_len);
	buf[15] = payload_len & 0x000000FF;
	buf[14] = (payload_len >> 8) & 0x000000FF;
}

void ccm_format_assoc_data(_BYTE buf[], int *end_of_buf, const _BYTE assoc[], int assoc_len)
{
	int pad;

	buf[*end_of_buf + 1] = assoc_len & 0x00FF;
	buf[*end_of_buf] = (assoc_len >> 8) & 0x00FF;
	*end_of_buf += 2;
	memcpy(&buf[*end_of_buf], assoc, assoc_len);
	*end_of_buf += assoc_len;
	pad = AES_BLOCK_SIZE - (*end_of_buf % AES_BLOCK_SIZE); /*BUG?*/
	memset(&buf[*end_of_buf], 0, pad);
	*end_of_buf += pad;
}

void ccm_format_payload_data(_BYTE buf[], int *end_of_buf, const _BYTE payload[], int payload_len)
{
	int pad;

	memcpy(&buf[*end_of_buf], payload, payload_len);
	*end_of_buf += payload_len;
	pad = *end_of_buf % AES_BLOCK_SIZE;
	if (pad != 0)
		pad = AES_BLOCK_SIZE - pad;
	memset(&buf[*end_of_buf], 0, pad);
	*end_of_buf += pad;
}

unsigned char *base64_encode(unsigned char *str, int str_len)
{
	long len;
	unsigned char *res;
	unsigned char *txt;
	int i, j;
	//定义base64编码表  
	char *base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

	if (str_len % 3 == 0)
		len = str_len / 3 * 4;
	else
		len = (str_len / 3 + 1) * 4;

	res = (unsigned char *)malloc(sizeof(unsigned char)*len + 1);
	res[len] = '\0';
	txt = (unsigned char *)malloc(sizeof(unsigned char)*len + 1);
	memset(txt, ' ', len);
	memcpy(txt, str, str_len);
	txt[len] = '\0';

	//以3个8位字符为一组进行编码  
	for (i = 0, j = 0; i<len - 2; j += 3, i += 4)
	{
		res[i] = base64_table[str[j] >> 2]; //取出第一个字符的前6位并找出对应的结果字符  
		res[i + 1] = base64_table[(str[j] & 0x3) << 4 | (str[j + 1] >> 4)]; //将第一个字符的后位与第二个字符的前4位进行组合并找到对应的结果字符  
		res[i + 2] = base64_table[(str[j + 1] & 0xf) << 2 | (str[j + 2] >> 6)]; //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符  
		res[i + 3] = base64_table[str[j + 2] & 0x3f]; //取出第三个字符的后6位并找出结果字符  
	}

	switch (str_len % 3)
	{
	case 1:
		res[i - 2] = '=';
		res[i - 1] = '=';
		break;
	case 2:
		res[i - 1] = '=';
		break;
	}

	free(txt);

	return res;
}

unsigned char *base64_decode(unsigned char *code, int len, int *str_len_ptr)
{
	int table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0,
		63, 52, 53, 54, 55, 56, 57, 58,
		59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0,
		1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
		13, 14, 15, 16, 17, 18, 19, 20, 21,
		22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26,
		27, 28, 29, 30, 31, 32, 33, 34, 35,
		36, 37, 38, 39, 40, 41, 42, 43, 44,
		45, 46, 47, 48, 49, 50, 51
	};
	int str_len;
	unsigned char *res;
	int i, j;

	//判断编码后的字符串后是否有=  
	if (strstr((char *)code, "=="))
		str_len = len / 4 * 3 - 2;
	else if (strstr((char *)code, "="))
		str_len = len / 4 * 3 - 1;
	else
		str_len = len / 4 * 3;

	res = (unsigned char *)malloc(sizeof(unsigned char)*str_len + 3);
	memset(res, ' ', str_len);
	res[str_len] = '\0';

	//以4个字符为一位进行解码  
	for (i = 0, j = 0; i < len - 2; j += 3, i += 4)
	{
		res[j] = ((unsigned char)table[code[i]]) << 2 | (((unsigned char)table[code[i + 1]]) >> 4); //取出第一个字符对应base64表的十进制数的前6位与第二个字符对应base64表的十进制数的后2位进行组合  
		res[j + 1] = (((unsigned char)table[code[i + 1]]) << 4) | (((unsigned char)table[code[i + 2]]) >> 2); //取出第二个字符对应base64表的十进制数的后4位与第三个字符对应bas464表的十进制数的后4位进行组合  
		res[j + 2] = (((unsigned char)table[code[i + 2]]) << 6) | ((unsigned char)table[code[i + 3]]); //取出第三个字符对应base64表的十进制数的后2位与第4个字符进行组合  
	}

	*str_len_ptr = str_len;

	return res;

}

static char error_message[50];

// 临界区处理
extern int FlagEn = 0;
#define  ENTER_CRITICAL()  FlagEn=1 
#define  EXIT_CRITICAL()   FlagEn=0

#define AES_KEY_SIZE 256

//AES_IV
static unsigned char AES_IV[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };

static unsigned char AES_KEY[32] = { 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 };

void setError(char *message)
{
	memcpy(error_message, message, strlen(message));
}

extern "C" __declspec(dllexport) char *getError()
{
	return error_message;
}

int get_aes256_encrypt_len(char *input) {
	int len = strlen((char *)input);
	// 需要补充的长度
	int padding_len = 16 - (len % 16);
	if (padding_len == 16) {
		padding_len = 0;
	}
	// 对齐后的长度
	return len + padding_len;
}

int aes256_encrypt(char *input, char * output, char *key)
{
	int len = strlen((char *)input);
	// 需要补充的长度
	int padding_len = 16 - (len % 16);
	if (padding_len == 16) {
		padding_len = 0;
	}
	// 对齐后的长度
	int dst_len = len + padding_len;
	int remain_len = dst_len;
	// 填充长度后的文本
	unsigned char *padding_txt = (unsigned char *)malloc((dst_len + 1)*sizeof(char));
	// aes256加密后的密文
	unsigned char *aes256_txt = (unsigned char *)malloc((dst_len + 1)*sizeof(char));
	// 输出区
	padding_txt[dst_len] = '\0';
	memset(padding_txt, ' ', dst_len);
	memcpy(padding_txt, input, len);

	_WORD key_schedule[AES_BLOCK_SIZE * 4] = { 0 };
	// 设置密钥
	aes_key_setup((unsigned char *)key, key_schedule, AES_KEY_SIZE);
	// 每次加密32位
	for (int i = 0; remain_len > 0; i++) {
		int offset = i * 16;
		int len_temp;
		if (remain_len >= 16) {
			len_temp = 16;
		}
		else {
			len_temp = remain_len;
		}
		aes_encrypt_cbc(padding_txt + offset, len_temp, aes256_txt + offset, key_schedule, AES_KEY_SIZE, AES_IV);
		remain_len -= 16;
	}
	aes256_txt[dst_len] = '\0';

	memcpy(output, aes256_txt, dst_len);
	output[dst_len] = '\0';

	free(padding_txt);
	free(aes256_txt);
	return 0;
}

int aes256_decrypt(char *input, char *output, char *key, int len)
{
	// base64解密后aes256再解密后的明文
	unsigned char *clear_txt = (unsigned char *)malloc((len + 1)*sizeof(char));
	unsigned char *cipher_txt = (unsigned char *)malloc((len + 1)*sizeof(char));
	memset(cipher_txt, '\0', len);
	memcpy(cipher_txt, input, len);
	// 剩余长度 用于aes256多次解密使用
	int remain_len = len;
	unsigned int key_schedule[AES_BLOCK_SIZE * 4] = { 0 };
	aes_key_setup((unsigned char *)key, key_schedule, AES_KEY_SIZE);
	// 每次解密128位,16个_BYTE
	for (int i = 0; remain_len > 0; i++) {
		int offset = i * 16;
		int len_temp;
		if (remain_len >= 16) {
			len_temp = 16;
		}
		else {
			len_temp = remain_len;
		}
		aes_decrypt_cbc(cipher_txt + offset, len_temp, clear_txt + offset, key_schedule, AES_KEY_SIZE, AES_IV);
		remain_len -= 16;
	}
	memcpy(output, clear_txt, len);
	output[len] = '\0';

	free(clear_txt);
	free(cipher_txt);
	return 0;
}

/*
* 通过指定文本,获取该文本加密后的密文长度
* 一般密文比数据长。
*
* @params input: 指定文本
* @return: 返回加密后的密文长度
*/
extern "C" __declspec(dllexport) int get_encrypt_len(char *input)
{
	int len = strlen((char *)input);
	int return_len;
	// 需要补充的长度
	int padding_len = 16 - (len % 16);
	if (padding_len == 16) {
		padding_len = 0;
	}
	// 对齐后的长度
	int dst_len = len + padding_len;

	if (dst_len % 3 == 0)
		return_len = dst_len / 3 * 4;
	else
		return_len = (dst_len / 3 + 1) * 4;
	return return_len;
}

/*
* 将input中的数据进行aes256 CBC模式加密后再BASE64加密。
*
* @params input: 指定文本
* @params output: 密文保存位置
* @params key: 256位密钥
* @return: 当调用成功时返回值为密文长度;失败时返回-1,并设置错误信息setError
*/
extern "C" __declspec(dllexport) int encrypt(char *input, char *output, char *key)
{
	if (!FlagEn) {
		ENTER_CRITICAL();
		if (strlen(key) < 32) {
			setError("The key length is less than 256 bits");
			return -1;
		}
		int len = strlen((char *)input);
		// 需要补充的长度
		int padding_len = 16 - (len % 16);
		if (padding_len == 16) {
			padding_len = 0;
		}
		// 对齐后的长度
		int dst_len = len + padding_len;
		int remain_len = dst_len;
		// 填充长度后的文本
		unsigned char *padding_txt = (unsigned char *)malloc((dst_len + 1)*sizeof(char));
		// aes256加密后的密文
		unsigned char *aes256_txt = (unsigned char *)malloc((dst_len + 1)*sizeof(char));
		// aes256加密后base64加密后的密文
		unsigned char *cipher = NULL;
		padding_txt[dst_len] = '\0';
		memset(padding_txt, ' ', dst_len);
		memcpy(padding_txt, input, len);

		aes256_encrypt((char *)padding_txt, (char *)aes256_txt, key);

		 后base64加密
		cipher = base64_encode(aes256_txt, dst_len);
		// 实际返回密文长度,因为base64会扩展长度
		int return_len = strlen((char *)cipher);
		memcpy(output, cipher, return_len);
		output[return_len] = '\0';

		free(padding_txt);
		free(aes256_txt);
		free(cipher);
		EXIT_CRITICAL();
		return return_len;
	}
	else {
		setError("Critical zone confilict!");
		return -1;
	}
}

/*
* 通过指定密文,获取该密文解密后的数据长度。
* 一般数据比密文短。
*
* @params input: 指定密文
* @return: 返回解密后的数据长度
*/
extern "C" __declspec(dllexport) int get_decrypt_len(char *input)
{
	int len = strlen((char *)input);
	int str_len;

	//判断编码后的字符串后是否有=  
	if (strstr((char *)input, "=="))
		str_len = len / 4 * 3 - 2;
	else if (strstr((char *)input, "="))
		str_len = len / 4 * 3 - 1;
	else
		str_len = len / 4 * 3;
	return str_len;
}

/*
* 将input中的密文进行BASE64解密,再进行aes256 CBC模式解密。
*
* @params input: 指定密文
* @params output: 数据保存位置
* @params key: 256位密钥
* @return: 当调用成功时返回值为明文长度;失败时返回-1,并设置错误信息setError
*/
extern "C" __declspec(dllexport) int decrypt(char *input, char *output, char *key)
{
	if (!FlagEn) {
		ENTER_CRITICAL();
		if (strlen(key) < 32) {
			setError("The key length is less than 256 bits");
			return -1;
		}
		int len = strlen(input);
		// base64解密后实际的长度
		int aes256_len;
		// base64解密后的密文
		unsigned char *base64_txt = base64_decode((unsigned char *)input, len, &aes256_len);
		// base64解密后aes256再解密后的明文
		unsigned char *clear_txt = (unsigned char *)malloc((aes256_len + 1)*sizeof(char));
		memset(clear_txt, '\0', aes256_len);

		aes256_decrypt((char *)base64_txt, (char *)clear_txt, key, aes256_len);

		memcpy(output, clear_txt, aes256_len);
		output[aes256_len] = '\0';

		free(clear_txt);
		free(base64_txt);
		EXIT_CRITICAL();
		return 0;
	}
	else {
		setError("Critical zone confilict!");
		return -1;
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: javasm2加密算法是一个基于椭圆曲线密码体制的非对称加密算法,它利用椭圆曲线上的点和点间的运算来实现加密和解密的过程。 具体的步骤如下: 1. 选择一个椭圆曲线参数集,包括曲线方程、椭圆曲线基点和曲线上的一个大整数N。 2. 选择一个私钥,即一个小于N的整数d作为加密方的私钥。 3. 根据私钥d计算公钥Q,即Q=d*G,其中G是椭圆曲线的基点。 4. 将待加密的明文转化为椭圆曲线上的点P,通过对明文进行哈希算法得到一个大整数H,然后将H与椭圆曲线的基点G相乘得到点P=H*G。 5. 选择一个随机数k,并计算点C1=k*G和C2=P+k*Q,其中C1和C2分别是加密后的曲线上的点。 6. 最终的密文为将C1和C2表示成字节串的形式。 对于解密过程,将C1和C2恢复成椭圆曲线上的点,即C1=k*G,C2=P+k*Q,然后通过计算C2-k*C1恢复出明文的点P,并将P转化成原始的明文。 javasm2加密算法通过利用椭圆曲线的数学性质,使得加密强度较高,同时运算速度也比较快。该算法被广泛应用于密码学领域,用于保护敏感信息的安全。 ### 回答2: JavaSM2是一种基于Java开发的SM2非对称加密算法的实现。SM2是中国自主研发的一种密码算法,其具有良好的安全性和高效性,特别适用于数字签名和密钥交换等场景。 JavaSM2的使用步骤如下: 1.生成密钥对:首先使用Java的密钥生成器生成SM2的公钥和私钥。公钥用于加密和验证数字签名,而私钥用于解密和生成数字签名。 2.加密数据:使用SM2的公钥对待加密的数据进行加密加密后的数据只能使用相应的私钥进行解密。 3.解密数据:使用SM2的私钥对加密后的数据进行解密,得到原始数据。 4.生成数字签名:使用SM2的私钥对待签名的数据进行签名,生成数字签名。数字签名用于验证数据的完整性和真实性。 5.验证数字签名:使用SM2的公钥对数字签名进行验证,确认数据的完整性和真实性。 JavaSM2的优点是具有较高的安全性,采用SM2算法可以保证数据的机密性和完整性。此外,它还具有高效性,能够在较短的时间内完成加密、解密和签名等操作。 总体而言,JavaSM2加密是一种安全可靠的加密算法实现,适用于各种安全通信和数据传输场景。 ### 回答3: JavaSM2是一种基于国密SM2算法的加密技术。SM2算法是中国自主研发的非对称加密算法,可用于数字签名、密钥交换和加密等安全通信应用。 JavaSM2加密C意味着使用Java语言实现SM2算法对C语言代码进行加密保护。加密过程大致分为三个步骤: 1. 密钥生成:首先需要生成SM2算法所需的密钥对,包括公钥和私钥。公钥用于加密,私钥用于解密。JavaSM2通过调用相关API生成密钥对。 2. 加密处理:将要加密C语言代码转化为字节流数据,再调用JavaSM2提供的API进行加密操作。加密后的数据将变得不可读且不易被篡改,提高代码的安全性。 3. 解密操作:将加密的数据传递给相应的解密方法,并使用私钥进行解密处理。解密后的数据将还原成原始的C语言代码,以便进行后续的使用和执行。 通过JavaSM2加密C语言代码可以提高代码的安全性,防止代码泄露和恶意篡改,保护软件的知识产权。同时也能够保护软件系统的安全,减少攻击者对系统的恶意入侵。因此,JavaSM2加密C语言代码在保障信息安全和知识产权保护方面具有重要的意义。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肥牛火锅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值