
#include <stdlib.h>
#include <apr_strings.h>
#include "SM4.h"

SM4::SM4(void)
{
}


SM4::~SM4(void)
{
}

unsigned char sm4_key[16];
//unsigned char *sm4_key="@XsdHUfb2ZajLeH3";
unsigned char kk_buf[]={0x20,0x38,0x53,0x44,0x28,0x35,0x46,0x42,0x12,0x3a,0x41,0x4a,0x2c,0x45,0x28,0x13};



/*
 * SM4 key schedule (128-bit, encryption)
 */
void SM4::sm4_setkey_enc( sm4_context *ctx, unsigned char key[16] )
{
    ctx->mode = SM4_ENCRYPT;
	sm4_setkey( ctx->sk, key );
}

/*
 * SM4 key schedule (128-bit, decryption)
 */
void SM4::sm4_setkey_dec( sm4_context *ctx, unsigned char key[16] )
{
    int i;
	ctx->mode = SM4_ENCRYPT;
    sm4_setkey( ctx->sk, key );
    for( i = 0; i < 16; i ++ )
    {
        SWAP( ctx->sk[ i ], ctx->sk[ 31-i] );
    }
}


/*
 * SM4-ECB block encryption/decryption
 */

void SM4::sm4_crypt_ecb( sm4_context *ctx,
				   int mode,
				   int length,
				   unsigned char *input,
                   unsigned char *output)
{
    while( length > 0 )
    {
        sm4_one_round( ctx->sk, input, output );
        input  += 16;
        output += 16;
        length -= 16;
    }

}

/*
 * SM4-CBC buffer encryption/decryption
 */
void SM4::sm4_crypt_cbc( sm4_context *ctx,
                    int mode,
                    int length,
                    unsigned char iv[16],
                    unsigned char *input,
                    unsigned char *output )
{
    int i;
    unsigned char temp[16];

    if( mode == SM4_ENCRYPT )
    {
        while( length > 0 )
        {
            for( i = 0; i < 16; i++ )
                output[i] = (unsigned char)( input[i] ^ iv[i] );

            sm4_one_round( ctx->sk, output, output );
            memcpy( iv, output, 16 );

            input  += 16;
            output += 16;
            length -= 16;
        }
    }
    else /* SM4_DECRYPT */
    {
        while( length > 0 )
        {
            memcpy( temp, input, 16 );
            sm4_one_round( ctx->sk, input, output );

            for( i = 0; i < 16; i++ )
                output[i] = (unsigned char)( output[i] ^ iv[i] );

            memcpy( iv, temp, 16 );

            input  += 16;
            output += 16;
            length -= 16;
        }
    }
}

//SM4加密
void SM4::sm4_enc(char *str,int nStrLen,char *result_out,unsigned char *smkey)
{
	unsigned int				i;
	unsigned char   full_str[128];
	unsigned char  tmpbuf[64];
	unsigned char   output[64];
	sm4_context     ctx;
	if(smkey==0) 	{for(i=0;i<16;i++) sm4_key[i]=kk_buf[i]+0x20;}
	else 			{for(i=0;i<16;i++) sm4_key[i]=smkey[i];}
	memset(full_str,0,100);				//不足16字节则补0
	memcpy(full_str,str, nStrLen);
	sm4_setkey_enc(&ctx,sm4_key);
	for(i=0,result_out[0]=0;i<((nStrLen +15)/16);i++)
	{
		sm4_crypt_ecb(&ctx,1,16,&full_str[i*16],output);
        apr_snprintf((char*)tmpbuf,sizeof(tmpbuf), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
			output[0],output[1],output[2],output[3],output[4],output[5],output[6],output[7],
			output[8],output[9],output[10],output[11],output[12],output[13],output[14],output[15]);
		strcat(result_out,(char*)tmpbuf);
	}
}
//SM4解密
void SM4::sm4_dec(char *str,char *result_out,unsigned char *smkey)
{
	unsigned int				i,j;
	sm4_context     ctx;
	unsigned char	input[64];
	unsigned char   output[64];
	char	convs[4]={0};
	if(smkey==0) 	{for(i=0;i<16;i++) sm4_key[i]=kk_buf[i]+0x20;}
	else 			{for(i=0;i<16;i++) sm4_key[i]=smkey[i];}
	sm4_setkey_dec(&ctx,sm4_key);
	for(i=0;i<strlen(str)/32;i++)   
	{
		for(j=0;j<16;j++) 
		{
			convs[0]=str[i*32+j*2+0];
			convs[1]=str[i*32+j*2+1];
			input[j]=strtol(convs,NULL,16);
		}
		sm4_crypt_ecb(&ctx,0,16,input,output);
		memcpy(&result_out[i*16],output,16);
	}
	result_out[i*16]=0;
}

