openssl编译arm移植及RSA_generate_key_ex的使用实例

测试 Linux linux 嵌入式

测试样例一

使用RSA密钥产生函数RSA_generate_key_ex生成了一对密钥

// demo.cpp
#include <stdio.h>
#include "openssl/rsa.h"
int main(){
    RSA *rsa = RSA_new();
    int ret = 0;
    BIGNUM* bne = BN_new();
    ret=BN_set_word(bne,RSA_F4);
    ret = RSA_generate_key_ex(rsa,512,bne,NULL);
    if(ret!=1){
        //FAILED
    }else{
        //SUCCESS
    }
    return 0;
}
$ g++ demo.cpp -I./openssl-1.1.0e/_install/include/openssl -I./openssl-1.1.0e/_install/include -L./ libcrypto.a libssl.a -lpthread -ldl

运行程序输出SUCCSS;

测试样例二

产生密钥,并使用公钥加密,使用私钥解密

#include <stdio.h>
#include <string.h>
#include <openssl/rsa.h>

int main()
{
    printf("\nRSA_generate_key_ex TESTING...\n\n");
    RSA *rsa = RSA_new();
    int ret = 0;
    BIGNUM *bne=BN_new();
    ret=BN_set_word(bne,RSA_F4);
    ret = RSA_generate_key_ex(rsa,512,bne,NULL);

    unsigned char plain[512]="Hello world!";
    unsigned char cipper[512]={0};
    unsigned char newplain[512]={0};
    size_t outl=512;
    size_t outl2;
    printf("%s\n", plain);
    for(int i =0;i<strlen((char*)plain);i++){
        printf("%02x ",plain[i]);
    }
    printf("\n---------------\n");
    outl=RSA_public_encrypt(strlen((char*)plain),plain,cipper,rsa,RSA_PKCS1_OAEP_PADDING);
    for(int i =0;i<outl;i++){
        printf("%02x ",cipper[i]);
        if((i+1)%10 ==0) printf("\n");
    }
    printf("\n");
    outl2=RSA_private_decrypt(outl,cipper,newplain,rsa,RSA_PKCS1_OAEP_PADDING);
    printf("-----------------\n%s\n", newplain);
    for(int i =0;i<outl2;i++) {
        printf("%02x ",newplain[i]);
    }
    printf("\n");
    return 0;
}
$ ./a.out 

RSA_generate_key_ex TESTING...

Hello world!
48 65 6c 6c 6f 20 77 6f 72 6c 64 21 
---------------
57 57 f1 3a 1b d9 60 e3 cd 4d 
41 35 a0 63 9b f3 1d e7 a8 d4 
3f a4 a3 25 66 ba 6b 9d 42 34 
7f 7b 1d 98 83 0b d9 47 8c 8b 
aa 81 f1 ed c5 45 04 f2 af f5 
98 30 de af ae d2 31 22 e1 32 
71 e7 c8 0b 
-----------------
Hello world!
48 65 6c 6c 6f 20 77 6f 72 6c 64 21 

开源库的编译

libcrypto.a,libssl.a库的编译;
开源库下载:https://www.openssl.org/source/
下载版本 openssl-1.1.0e.tar.gz

$ ./config no-asm shared --prefix=$PWD/_install

编译产生四个库 libcrypto.a libcrypto.so libssl.a libssl.so;
拷贝库文件出来,编译demo.cpp的目录结构:

|---demo.cpp
|---libcrypto.a
|---libssl.a
|---openssl-1.1.0e/
|---openssl-1.1.0e/_install/
|---openssl-1.1.0e/_install/include/
|---openssl-1.1.0e/_install/include/openssl/

网上大部分例程是使用了openssl-1.1.0e之前的版本,在该版本之前产生密钥都是使用了RSA_generate_key;
但是在openssl-1.1.0e版本上使用RSA_generate_key,编译阶段警告
RSA_generate_key…is deprecated…
在新版本中建议使用RSA_generate_key_ex;

开源库的移植

$ ./config no-asm no-static-engine enable-shared --cross-compile-prefix=arm-none-linux-gnueabi-
$ ./Configure linux-elf no-asm no-static-engine enable-shared --cross-compile-prefix=arm-none-linux-gnueabi-
$ make
$ make install

或者根据需要加入安装路径参数

--prefix=$PWD/_install

编译的是arm构架的库,所以修改 linux-elf 为 linux-armv4 使用仍然正常;
编译测试样例一、样例二成功并运行输出正确结果;
编译可执行程序的Makefile:

all:
    arm-none-linux-gnueabi-g++ demo.cpp \
    -I/home/admin/project/debug/openssl-1.1.0e/include  \
    ${addprefix -L,/home/admin/project/debug/openssl-1.1.0e/lib}   \
    -lssl -lcrypto -lm -lpthread -ldl

测试过程中使用了大概有4个版本的openssl库
openssl-1.0.2
openssl-1.0.2l
openssl-1.0.2j
openssl-1.1.0e

开源库移植过程出现的问题

在移植过程中发生了一些意外,如果使用下面的配置编译会出现问题(直接gcc基础上加上cross-compile-prefix)
而不配置Configure的相关属性

$ ./config no-asm shared --prefix=$PWD/_install --cross-compile-prefix=arm-none-linux-gnueabi-
$ make

产生两个问题
1 编译时报m64字段的错误(需要手动删除Makefile文件中的两处m64字段)
2 在开发板上运行报错,并且编译阶段就有警告(getcontext/setcontext/makecontext未实现,允许忽略不处理)
3 编译后的应用程序使用报错(crypto/bn/bn_gcd.c/BN_mod_inverse函数产生BIGNUM的d[0]错误参数)

于是写了DEMO:

#include <stdio.h>
#include "openssl/rsa.h"

int main(){
    RSA * rsa =RSA_generate_key(1024,RSA_3,NULL,NULL);
    printf("%p\n", rsa);
    return 0;
}

编译的测试样例一也是出现一样的错误(BIGNUM的d[0]参数错误);

在宿主机上运行正确;在板子上运行则是进入了死循环;
使用交叉编译工作编译时,在编译阶段出现的警告

warning: warning: getcontext is not implemented and will always fail
warning: warning: setcontext is not implemented and will always fail
warning: warning: makecontext is not implemented and will always fail

setcontext和getcontext的使用
下面使用测试程序测试 setcontext ,getcontext ,makecontext 三个接口,是否能够在arm的板子上正确运行:
来自维基百科Setcontext条目的demo https://en.wikipedia.org/wiki/Setcontext

// ucontext.cpp
#include <stdio.h>
#include <ucontext.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    ucontext_t context;
    getcontext(&context);
    puts("Hello world");
    sleep(1);
    setcontext(&context);
    return 0;
}

运行:

$ g++ ucontext.cpp
$ ./a.out 
Hello world
Hello world
Hello world
Hello world
Hello world

This makes an infinite loop because context holds the program counter.
(这是一个无限循环因为语境保持程序计数器.)

使用交叉编译工具在开发板上进行测试

$ arm-none-linux-gnueabi-g++ ucontext.cpp 
/tmp/ccSGOIfY.o: In function `main':
ucontext.cpp:(.text+0x1c): warning: warning: getcontext is not implemented and will always fail
ucontext.cpp:(.text+0x38): warning: warning: setcontext is not implemented and will always fail
$ ./a.out 
$ Hello world
$

在Linux嵌入式板子上运行后,没有循环输出 Hello world;

暂时没有找到较为完整的解决办法,建议使用线程(pthread)或者互斥锁来实现相同的功能;

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值