• RSA加密及加签


    1.对方要求我们的私钥是pkcs8格式,但是实际的公钥没有用pkcs8转换之后的私钥完成,所以是可以不是pkcs8的格式的。我们加签跟格式没有关系。
    2.数据格式很重要,to_mpint而非crypto:mpint生成mpint的高精度整型,to_mpint有是自己写的函数,但实际上有很多开源代码里面有,所以要多看开源代码及想到直接调用。
    3.RSA加密加签原理:
    (1).加密,可以用私钥加密,公钥解密。
    (2).加密,也可以用公钥加密,私钥解密。
    (3).加签,必须要用私钥加签,公钥验证。
    (4).调用的方法不同。原理如下:
    RSA数据的hash^私钥 mod M = 签名
    签名 ^公钥 mod M = 数据的hash
    数据 ^公钥 mod M = 密文
    密文 ^私钥 mod M = 数据
    4.调用erlang的crypto模块加密
    5.生成密钥的方法是一样的。
    (1).按装openssl(基础环境中有此软件,无需安装)
    (2).输入openssl
    生成私钥: genrsa -out private_key.pem 1024
    (3).转换成pkcs8格式(可无)pkcs8 -topk8 -inform PEM -in private_key.pem -outform PEM -nocrypt -out rsa_private_key.pem
    (4).用私钥生成公钥: rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
    6.对于加签,是使用crypto:rsa_sign还是crypto:sign,但是实际上sign是新版本的,我方安装版本跟不上。
    7.对于未做过的操作,应该有几步:
    (1)确认要使用的方法
    (2)对于该方法所要的参数,如果格式不符合,要找到对应的转换方式(可以看开源库)
    但是方向要弄对,要先找到解决方法,再找原因。
    ====================================加密================================================
    加密(用私钥加密,公钥解密)
    -module(crypto_api).
    -include_lib("public_key/include/public_key.hrl").
    -include("ewp.hrl").
    -include("backend.hrl").
    -export([testencode/1,%%测试加密函数
    testdecode/1 %%测试解密函数
    ]).
    %%Params为原始内容,数据类型为binary,_Foo为加密后的密文
    case Type of
    RSA ->
    crypttest:testencode(Mobile); crypto_api:testencode()
    _ ->
    sm:
    testencode(Params) ->
    {ok, PemBinary} = file:read_file("./public/security/rsa_private_key.pem"),%%读取私钥中的pem二进制码
    [Entry] = public_key:pem_decode(PemBinary),%%读取私钥中的pem二进制码,生产一个实体
    RSAPrivateKey = public_key:pem_entry_decode(Entry),%%实体生产私钥Key
    %%调用erlang的crypto模块加密
    PrivKey = [crypto:mpint(RSAPrivateKey#'RSAPrivateKey'.publicExponent), crypto:mpint(RSAPrivateKey#'RSAPrivateKey'.modulus), crypto:mpint(RSAPrivateKey#'RSAPrivateKey'.privateExponent)] ,
    _Foo = crypto:rsa_private_encrypt(Params,PrivKey,rsa_pkcs1_padding).

    testdecode(Params) ->
    {ok, PemBinary} = file:read_file("./public/security/rsa_public_key.pem"),
    [Entry] = public_key:pem_decode(PemBinary),
    RSAPublicKey = public_key:pem_entry_decode(Entry),
    PubKey = [crypto:mpint(RSAPublicKey#'RSAPublicKey'.publicExponent), crypto:mpint(RSAPublicKey#'RSAPublicKey'.modulus)],
    _Bar = crypto:rsa_public_decrypt(Params,PubKey,rsa_pkcs1_padding).


    ============================加签,MD5摘要生成=======================================================
    -module(....).

    -include("ewp.hrl").
    -include("backend.hrl").
    -include_lib("public_key/include/public_key.hrl").
    -define(URL,"https://jiaofei........html").

    -export([
    'SN0001'/3, % 第三方配置化
    proplist_to_andlist/1
    ]).

    'SN0001'(UserObj, TranID, P) ->
    MOBILE_NO = user_obj:get_field('MOBILE_NO', UserObj), %% 手机号
    USER_CODE = user_obj:get_field('USER_CODE', UserObj), %% 手机银行客户号
    Url = ?URL,
    RequestTime = "20170214142901", %%ewp_time:datetime_str()
    Version = "2.0", %
    App_id = "yfbm70058192e2017021301", %
    Merchant_user_no = "43243", %%商户id之后给 USER_CODE
    Terminal_type = "03",
    Sign_type = "RSA",
    Signkey_index = "0001", %%公钥索引 测试
    SignMD = list_to_possign([{"request_time",RequestTime},{"version",Version},{"app_id",App_id}, {"merchant_user_no",Merchant_user_no},{"terminal_type",Terminal_type}]), %%数字签名
    {ok, Privatekey} = file:read_file("./config/key/private_key.pem"),%%读取私钥中的pem二进制码
    SignRSA = rsa_encode(SignMD,Privatekey),
    Sign = yaws_api:url_encode(SignRSA),
    PostDetail = Sign, %%实际要post给苏宁的参数
    [{url,Url},{post,PostDetail}].

    rsa_encode(Data,Priv_key) ->
    [Entry] = public_key:pem_decode(Priv_key), %%读取私钥中的pem二进制码,生产一个实体
    RSAPrivateKey = public_key:pem_entry_decode(Entry), %%实体生产私钥Key 私钥加密 加密的时候传参数为二进制的
    PrivKey = [crypto:mpint(RSAPrivateKey#'RSAPrivateKey'.publicExponent),
    crypto:mpint(RSAPrivateKey#'RSAPrivateKey'.modulus), crypto:mpint(RSAPrivateKey#'RSAPrivateKey'.privateExponent)],
    Result = crypto:rsa_sign('sha',to_mpint(Data),PrivKey), %% crypto:rsa_sign('sha',NumberMpint,PrivKey) crypto:sign(rsa,md5,Number,PrivKey)
    ResultBase = base64:encode(Result),
    binary_to_list(ResultBase). %% 传回后台使用 变回字符串的类型

    to_mpint(String) when is_list(String) ->
    to_mpint(list_to_binary(String));
    to_mpint(Bin) ->
    Size = size(Bin),
    <<Size:32/integer, Bin:Size/binary>>.

    %% params: Proplist为[{...},.tuple..,{...}]格式。
    %% 返回结果:key=value&key1=value1....
    proplist_to_andlist(Proplist)->
    Str1 = lists:foldl(
    fun(X,Acc)->
    {Key1,Value1} = X,
    Key = atom_to_string(Key1),
    Value = atom_to_string(Value1),
    case [Key,Value] of
    [_,""] ->
    Acc; %%如果值为空,不放入该序列
    [_," "] ->
    Acc;
    _ ->
    case Acc of
    [] ->
    Acc ++ Key ++ "=" ++ Value;
    " " ->
    Acc ++ Key ++ "=" ++ Value;
    _ ->
    Acc ++ "&" ++ Key ++ "=" ++ Value
    end
    end
    end,"",Proplist),
    Str1.

    %% params: Proplist为[{...},.tuple..,{...}]格式。
    %% 返回结果:数字签名---MD5加密后的大写的16进制(按照微信规则商户支付密钥放置在串最后加密)
    list_to_possign(Proplist)->
    SortList = lists:keysort(1,Proplist), %%ASC码从小到大排序
    Str1 = proplist_to_andlist(SortList), %%拼接成 Key1=value1&Key2=value2 无key商户支付密钥的序列
    Res1 = Str1,
    MD1 = erlang:md5(Res1), %%
    <<Int:128>> = MD1, %% MD2 = backend_util:to_hexstr(MD1)
    Str = integer_to_list(Int,16), %%生成大写的16进制
    Str.

    %% 如果参数A为atom则转换为string,如果本来就是string则还是string
    atom_to_string(A)->
    case is_atom(A) of
    true ->
    atom_to_list(A);
    false ->
    A
    end.

  • 相关阅读:
    读写文件流
    关闭和退出窗口
    有什么问题?
    将aspx页面转换成htm页面
    读取rss聚合文件
    运算符重载实例
    委托
    将 Visual Studio .NET 调试器用于 ASP.NET 应用程序
    输入的字符串进行有规则的清洗
    几个常用的数据库连接字符串
  • 原文地址:https://www.cnblogs.com/weidongprefer/p/6417352.html
Copyright © 2020-2023  润新知