openssl学习篇之base64编码、解码
2016-03-19 14:06
435 查看
因为拓展开发平台的原因,想把某网站的功能移植到手机客户端。决定先从IOS下手,但是服务器上的应用是基于 .net开发,
加密和解密算法与 objective-c下的算法并不一致,由此产生使用openssl库的想法,以确保在 IOS 和Android上都能运行一致。
但是openssl并不是有现成的函数供调用,需要自己写接口。
就以最基本的base64 编码和解码为例,也花了笔者若干天时间,现将过程记录如下 ,以飨后者。
步骤 1.
当然是从 www.openssl.org 处下载 openssl 库 ,当时版本是 1.0.1c,下载完了,要安装cygwin或是active perl
将压缩包编译成能在windows平台下使用的 dll和lib (这儿就不再赘述了,网上N多资料)
步骤 2.
由于base64编码的运算在 openssl中有很多的实现方式: BIO EVP,后者新点,但是也是自己写步骤,
a.可以直接使用EVP_EncodeBlock(...) / EVP_DecodeBlock(...) 编码、解码
b.使用EVP_EncodeInit + EVP_EncodeUpdate + EVP_EncodeFinal / EVP_DecodeInit + EVP_DecodeUpdate + EVP_DecodeFinal 组合进行
经过比照后,采用了后一种方式
步骤 3.
写自己的接口
接口中调用的函数声明如下:
#define IN
#define OUT
extern "C" __declspec(dllexport) int base64encode(
IN const unsigned char *in,//输入字串
IN int inl,//输入字串的长度
IN OUT unsigned char *out
);
extern "C" __declspec(dllexport) int base64decode(
IN const unsigned char *in,//输入字串
IN int inl,
IN OUT unsigned char *out
);
在需要调用功能的其他项目文件处声明入口
[DllImport(@"Base64Test.dll", CharSet = CharSet.Auto, EntryPoint = "base64encode", CallingConvention = CallingConvention.Cdecl)]
public static extern int base64encode(StringBuilder __in, int inl, StringBuilder __out);
[DllImport(@"Base64Test.dll", CharSet = CharSet.Auto, EntryPoint = "base64decode", CallingConvention = CallingConvention.Cdecl)]
public static extern int base64decode(StringBuilder __in, int inl, StringBuilder __out);
在测试时编码一直不正确,出现了字符是非标准ascii码表中的字符,后经朋友 西门 提醒,unsigned char* 可以被当作是 byte[]处理
这样,将入口函数声明修改为
[DllImport(@"Base64Test.dll", CharSet = CharSet.Auto, EntryPoint = "base64encode", CallingConvention = CallingConvention.Cdecl)]
public static extern int base64encode(byte[] __in, int inl, byte[] __out);
[DllImport(@"Base64Test.dll", CharSet = CharSet.Auto, EntryPoint = "base64decode", CallingConvention = CallingConvention.Cdecl)]
public static extern int base64decode(byte[] __in, int inl, byte[] __out);
测试后,发现英文字符正常,但是如果有中文字符,就会出现错误,后来发现 是因为传入参数 inl 的问题,在计算时,没有考虑到中文字符 是占3个byte,完全修正后代码如下:
接口项目名为: Base64Test
/************************************************Base64Test.h*********************************************************************/
#define IN
#define OUT
#define SUCCESS 0
#define INPUT_ERROR -1
#define OUTPUT_BUFFER_NOT_READY -2
extern "C" __declspec(dllexport) int base64encode(
IN const unsigned char *in,//输入字串
IN int inl,//输入字串的长度
IN OUT unsigned char *out
);
extern "C" __declspec(dllexport) int base64decode(
IN const unsigned char *in,//输入字串
IN int inl,
IN OUT unsigned char *out
);
int SizeOfUnsignedChar(unsigned char *p);
/*************************************Base64Test.cpp***************************************************************************/
#include "stdafx.h"
#include <string.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include "Base64Test.h"
/**
*Use EVP to Base64 encode the input byte array to readable text
*/
int base64encode(
IN const unsigned char *in,
IN int inl,
IN OUT unsigned char *out
)
{
if(in==NULL)
return INPUT_ERROR;
if(out==NULL)
return OUTPUT_BUFFER_NOT_READY;
if(inl<=0)
return INPUT_ERROR;
EVP_ENCODE_CTX ctx;
int base64Len= (((inl+2)/3)*4)+1;//Base 64 text length
int pemLen=base64Len+base64Len/64;// PEM adds a newline every 64 bytes
unsigned char* base64=new unsigned char[pemLen];
int ret;
EVP_EncodeInit(&ctx);
EVP_EncodeUpdate(&ctx,(unsigned char*)base64,&ret,(unsigned char*) in ,inl);
EVP_EncodeFinal(&ctx,(unsigned char*)&base64[ret],&ret);
memset(out, 0, ret);
memcpy(out,base64,ret);
if(base64 != NULL)
{
delete [] base64;
base64 = NULL;
}
return ret;
}
/**
*Use EVP to Base64 decode the input readable text to original bytes
*/
int base64decode(IN const unsigned char *in,
IN int inl,
IN OUT unsigned char *out
)
{
if(in==NULL)
return INPUT_ERROR;
if(out==NULL)
return OUTPUT_BUFFER_NOT_READY;
if(inl<=0)
return INPUT_ERROR;
EVP_ENCODE_CTX ctx;
int orgLen = (((inl+2)/4)*3) + 1;
unsigned char* orgBuf=new unsigned char[orgLen];
int ret, tmpLen;
EVP_DecodeInit(&ctx);
EVP_DecodeUpdate(&ctx,(unsigned char*)orgBuf,&ret,(unsigned char*)in,inl);
EVP_DecodeFinal(&ctx,(unsigned char*)orgBuf,&tmpLen);
ret+=tmpLen;
memset(out, 0, ret);
memcpy(out,orgBuf,ret);
if(orgBuf != NULL)
{
delete [] orgBuf;
orgBuf = NULL;
}
return ret;//如果成功,返回编码后的字符长度
}
int SizeOfUnsignedChar(unsigned char *p)
{
int n = 0;
while(*(p++))
{
n++;
if(n==INT_MAX)
return -1;
}
return n;
}
/*************************************myApp.cs****************************************/
...
...
private string __Base64Encode(string data)
{
if (!string.IsNullOrEmpty(data))
{
byte[] encData_byte = System.Text.Encoding.UTF8.GetBytes(data);
int __inl = System.Text.Encoding.UTF8.GetByteCount(data);//这种长度计算方式考虑了字符中如果有非标字符会占用多个字节的情况,原来就简单的使用了 data.Length
int base64Len = (((__inl + 2) / 3) * 4) + 1;//Base 64 text length
int pemLen = base64Len + base64Len / 64;// PEM adds a newline ever
byte[] retData_byte = new byte[pemLen];
int __retl = base64encode(encData_byte, __inl, retData_byte);
int charCount = (new System.Text.UTF8Encoding().GetDecoder()).GetCharCount(retData_byte, 0, retData_byte.Length);
char[] _ret = new char[charCount];
(new System.Text.UTF8Encoding().GetDecoder()).GetChars(retData_byte, 0, retData_byte.Length, _ret, 0);
return System.Text.RegularExpressions.Regex.Replace(new String(_ret), @"[\r\n\s\0]*$", "");
}
else
{
return "";
}
}
private string __Base64Decode(string data)
{
if (!string.IsNullOrEmpty(data))
{
byte[] decData_byte = System.Text.Encoding.UTF8.GetBytes(data);
int __inl = System.Text.Encoding.UTF8.GetByteCount(data);
int orgLen = (((__inl + 2) / 4) * 3) + 1;
byte[] retData_byte = new byte[orgLen];
int __retl = base64decode(decData_byte, __inl, retData_byte);
int charCount = (new System.Text.UTF8Encoding().GetDecoder()).GetCharCount(retData_byte, 0, retData_byte.Length);
char[] _ret = new char[charCount];
(new System.Text.UTF8Encoding().GetDecoder()).GetChars(retData_byte, 0, retData_byte.Length, _ret, 0);
return System.Text.RegularExpressions.Regex.Replace(new String(_ret), @"[\r\n\s\0]*$", "");
}
else
{
return "";
}
}
/***********************************************
9775
**********ACKNOWLEDGE*****************************************************************************/
感谢友人西门提醒了我 byte[]的关键作用、 Base64Test.cpp 中代码参考了CSDN 网友的博客
加密和解密算法与 objective-c下的算法并不一致,由此产生使用openssl库的想法,以确保在 IOS 和Android上都能运行一致。
但是openssl并不是有现成的函数供调用,需要自己写接口。
就以最基本的base64 编码和解码为例,也花了笔者若干天时间,现将过程记录如下 ,以飨后者。
步骤 1.
当然是从 www.openssl.org 处下载 openssl 库 ,当时版本是 1.0.1c,下载完了,要安装cygwin或是active perl
将压缩包编译成能在windows平台下使用的 dll和lib (这儿就不再赘述了,网上N多资料)
步骤 2.
由于base64编码的运算在 openssl中有很多的实现方式: BIO EVP,后者新点,但是也是自己写步骤,
a.可以直接使用EVP_EncodeBlock(...) / EVP_DecodeBlock(...) 编码、解码
b.使用EVP_EncodeInit + EVP_EncodeUpdate + EVP_EncodeFinal / EVP_DecodeInit + EVP_DecodeUpdate + EVP_DecodeFinal 组合进行
经过比照后,采用了后一种方式
步骤 3.
写自己的接口
接口中调用的函数声明如下:
#define IN
#define OUT
extern "C" __declspec(dllexport) int base64encode(
IN const unsigned char *in,//输入字串
IN int inl,//输入字串的长度
IN OUT unsigned char *out
);
extern "C" __declspec(dllexport) int base64decode(
IN const unsigned char *in,//输入字串
IN int inl,
IN OUT unsigned char *out
);
在需要调用功能的其他项目文件处声明入口
[DllImport(@"Base64Test.dll", CharSet = CharSet.Auto, EntryPoint = "base64encode", CallingConvention = CallingConvention.Cdecl)]
public static extern int base64encode(StringBuilder __in, int inl, StringBuilder __out);
[DllImport(@"Base64Test.dll", CharSet = CharSet.Auto, EntryPoint = "base64decode", CallingConvention = CallingConvention.Cdecl)]
public static extern int base64decode(StringBuilder __in, int inl, StringBuilder __out);
在测试时编码一直不正确,出现了字符是非标准ascii码表中的字符,后经朋友 西门 提醒,unsigned char* 可以被当作是 byte[]处理
这样,将入口函数声明修改为
[DllImport(@"Base64Test.dll", CharSet = CharSet.Auto, EntryPoint = "base64encode", CallingConvention = CallingConvention.Cdecl)]
public static extern int base64encode(byte[] __in, int inl, byte[] __out);
[DllImport(@"Base64Test.dll", CharSet = CharSet.Auto, EntryPoint = "base64decode", CallingConvention = CallingConvention.Cdecl)]
public static extern int base64decode(byte[] __in, int inl, byte[] __out);
测试后,发现英文字符正常,但是如果有中文字符,就会出现错误,后来发现 是因为传入参数 inl 的问题,在计算时,没有考虑到中文字符 是占3个byte,完全修正后代码如下:
接口项目名为: Base64Test
/************************************************Base64Test.h*********************************************************************/
#define IN
#define OUT
#define SUCCESS 0
#define INPUT_ERROR -1
#define OUTPUT_BUFFER_NOT_READY -2
extern "C" __declspec(dllexport) int base64encode(
IN const unsigned char *in,//输入字串
IN int inl,//输入字串的长度
IN OUT unsigned char *out
);
extern "C" __declspec(dllexport) int base64decode(
IN const unsigned char *in,//输入字串
IN int inl,
IN OUT unsigned char *out
);
int SizeOfUnsignedChar(unsigned char *p);
/*************************************Base64Test.cpp***************************************************************************/
#include "stdafx.h"
#include <string.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include "Base64Test.h"
/**
*Use EVP to Base64 encode the input byte array to readable text
*/
int base64encode(
IN const unsigned char *in,
IN int inl,
IN OUT unsigned char *out
)
{
if(in==NULL)
return INPUT_ERROR;
if(out==NULL)
return OUTPUT_BUFFER_NOT_READY;
if(inl<=0)
return INPUT_ERROR;
EVP_ENCODE_CTX ctx;
int base64Len= (((inl+2)/3)*4)+1;//Base 64 text length
int pemLen=base64Len+base64Len/64;// PEM adds a newline every 64 bytes
unsigned char* base64=new unsigned char[pemLen];
int ret;
EVP_EncodeInit(&ctx);
EVP_EncodeUpdate(&ctx,(unsigned char*)base64,&ret,(unsigned char*) in ,inl);
EVP_EncodeFinal(&ctx,(unsigned char*)&base64[ret],&ret);
memset(out, 0, ret);
memcpy(out,base64,ret);
if(base64 != NULL)
{
delete [] base64;
base64 = NULL;
}
return ret;
}
/**
*Use EVP to Base64 decode the input readable text to original bytes
*/
int base64decode(IN const unsigned char *in,
IN int inl,
IN OUT unsigned char *out
)
{
if(in==NULL)
return INPUT_ERROR;
if(out==NULL)
return OUTPUT_BUFFER_NOT_READY;
if(inl<=0)
return INPUT_ERROR;
EVP_ENCODE_CTX ctx;
int orgLen = (((inl+2)/4)*3) + 1;
unsigned char* orgBuf=new unsigned char[orgLen];
int ret, tmpLen;
EVP_DecodeInit(&ctx);
EVP_DecodeUpdate(&ctx,(unsigned char*)orgBuf,&ret,(unsigned char*)in,inl);
EVP_DecodeFinal(&ctx,(unsigned char*)orgBuf,&tmpLen);
ret+=tmpLen;
memset(out, 0, ret);
memcpy(out,orgBuf,ret);
if(orgBuf != NULL)
{
delete [] orgBuf;
orgBuf = NULL;
}
return ret;//如果成功,返回编码后的字符长度
}
int SizeOfUnsignedChar(unsigned char *p)
{
int n = 0;
while(*(p++))
{
n++;
if(n==INT_MAX)
return -1;
}
return n;
}
/*************************************myApp.cs****************************************/
...
...
private string __Base64Encode(string data)
{
if (!string.IsNullOrEmpty(data))
{
byte[] encData_byte = System.Text.Encoding.UTF8.GetBytes(data);
int __inl = System.Text.Encoding.UTF8.GetByteCount(data);//这种长度计算方式考虑了字符中如果有非标字符会占用多个字节的情况,原来就简单的使用了 data.Length
int base64Len = (((__inl + 2) / 3) * 4) + 1;//Base 64 text length
int pemLen = base64Len + base64Len / 64;// PEM adds a newline ever
byte[] retData_byte = new byte[pemLen];
int __retl = base64encode(encData_byte, __inl, retData_byte);
int charCount = (new System.Text.UTF8Encoding().GetDecoder()).GetCharCount(retData_byte, 0, retData_byte.Length);
char[] _ret = new char[charCount];
(new System.Text.UTF8Encoding().GetDecoder()).GetChars(retData_byte, 0, retData_byte.Length, _ret, 0);
return System.Text.RegularExpressions.Regex.Replace(new String(_ret), @"[\r\n\s\0]*$", "");
}
else
{
return "";
}
}
private string __Base64Decode(string data)
{
if (!string.IsNullOrEmpty(data))
{
byte[] decData_byte = System.Text.Encoding.UTF8.GetBytes(data);
int __inl = System.Text.Encoding.UTF8.GetByteCount(data);
int orgLen = (((__inl + 2) / 4) * 3) + 1;
byte[] retData_byte = new byte[orgLen];
int __retl = base64decode(decData_byte, __inl, retData_byte);
int charCount = (new System.Text.UTF8Encoding().GetDecoder()).GetCharCount(retData_byte, 0, retData_byte.Length);
char[] _ret = new char[charCount];
(new System.Text.UTF8Encoding().GetDecoder()).GetChars(retData_byte, 0, retData_byte.Length, _ret, 0);
return System.Text.RegularExpressions.Regex.Replace(new String(_ret), @"[\r\n\s\0]*$", "");
}
else
{
return "";
}
}
/***********************************************
9775
**********ACKNOWLEDGE*****************************************************************************/
感谢友人西门提醒了我 byte[]的关键作用、 Base64Test.cpp 中代码参考了CSDN 网友的博客
相关文章推荐
- OpenCV IplImage结构体
- nginx+tomcat均衡负载实践
- linux 内核线程demo
- centos7 安装php-7.0.4
- 用VNC 客户端如何查看openstack 创建的虚拟机
- 20135316王剑桥Linux内核学习笔记第四周
- Linux学习笔记(9)----shell script
- iOS应用架构谈 本地持久化方案
- iOS应用架构谈 动态部署方案
- Linux笔记(58)——详解apache源码包安装
- shell编程:自动格式化硬盘并挂载
- Tomcat Server组成
- 磁盘和文件系统管理(1)
- iOS 应用架构谈:view 层的组织和调用方案
- 高效分布式计算系统之—Spark与Hadoop
- VS2003安装Opencv1.0 windows系统 win7
- iOS 架构 (一)
- An internal error occurred during: "Add Deployment".
- Storm架构分析
- 实例解析linux内核I2C体系结构(1)