盛世宏图 发表于 2022-6-24 13:35:49

ABAP RSA方式调用银行API

一、RSA简介

RSA是非对称加密的一种。
对称加密算法在加密和解密时使用的是同一个秘钥;
非对称加密算法需要一对密钥来加密解密,这两个密钥是公开密钥(public key,简称公钥)和私有密钥(private key,简称私钥)。一个加密,一个解密,由双方各保留一个进行操作。这样,在不传输秘钥的情况下,双方可以针对信息进行加解密,避免了直接传输秘钥可能导致的安全问题。
二、RSA加解密与签名验签

一般来说,有两种场景:加密解密和签名验签
加密解密:使用公钥加密,私钥解密
签名验签:使用私钥加密(签名),公钥解密(验签)
例如:B生成一对密钥,向A提供公钥,B保留私钥
加密:防止信息泄露
当A系统传输数据给B系统,担心报文明文传输会导致信息泄露,则可使用公钥对报文进行加密,以防传输过程中信息泄露。B接收加密报文,通过私钥进行解密
签名:防止信息篡改
当B接收后返回消息给A,担心返回消息被修改,A接收到错误消息,则可使用秘钥进行签名,并将签名和返回报文一起发送给A。A通过公钥进行验签,发现签名解析后和返回报文数据一致,证明报文没有被中间拦截篡改
三、代码实现

1、证书加密解密与签名验签

使用秘钥生成PSE证书方式进行加密解密与签名验签
生成一对密钥后,将私钥文件RSA.key上传到SAP服务器,前后需要加标注,否则不能正常使用
https://img2022.cnblogs.com/blog/1225252/202206/1225252-20220613162128534-8753874.png
通过命令生成PSE文件,此操作需要BASIS协助
/tmp/rsa > openssl req -x509 -sha256 -key rsa.key -out user1.cer -days 3650 -subj '/CN=user1'
/tmp/rsa > openssl pkcs12 -export -inkey rsa.key -in user1.cer -out user1.pfx -nodes
Enter Export Password:
Verifying - Enter Export Password:
/tmp/rsa > setenv SECUDIR $PWD
/tmp/rsa > sapgenpse import_p12 -x "" -p user1.pse user1.pfx
Found key 'INDEX=0,SIG=YES,ENC=YES,MD5-FINGERPRINT=3B9E 77DD E5E4 3371 19FA 2FCF D1CA 512F,KEYID=3D1E2BC7E33500A3D2A098B63FE9962A6B63318C'

!!! WARNING: For security reasons it is recommended to use a PIN/passphrase
!!! WARNING: which is at least 8 characters long and contains characters in
!!! WARNING: upper and lower case, numbers and non-alphanumeric symbols.

PSE "/tmp/rsa/user1.pse" was written证书加密解密代码:

DATA: lv_output         TYPE xstring,
      lv_input_x      TYPE xstring,
      lv_input          TYPE string,
      lt_recipient_list TYPE STANDARD TABLE OF ssfinfo,
      ls_recipient_list LIKE LINE OF lt_recipient_list,
      lv_crc            TYPE ssfparms-ssfcrc.

DATA: lf_output      TYPE xstring.
DATA: lf_plain_input_x TYPE xstring.
DATA: lf_plain_input   TYPE string.
DATA: msg_file_name    TYPE string.
DATA: it_recipient_list TYPE STANDARD TABLE OF ssfinfo,
      wa_recipient_list LIKE LINE OF it_recipient_list.

"原文
lf_plain_input = '一段需要处理的报文'.

"转为xstring
CALLFUNCTION'SCMS_STRING_TO_XSTRING'
EXPORTING
    text =lf_plain_input
IMPORTING
    buffer =lf_plain_input_x.

"证书域名
wa_recipient_list-id ='CN=user1'.
APPENDwa_recipient_listTOit_recipient_list.

"加密函数
CALLFUNCTION'SSFW_KRN_ENVELOPE'
EXPORTING
    str_format ='PKCS1-V1.5'
    str_pab ='/tmp/rsa/user1.pse'"服务器中证书路径
    ostr_input_data =lf_plain_input_x
IMPORTING
    ostr_enveloped_data =lf_output
TABLES
    recipient_list =it_recipient_list
EXCEPTIONS
    OTHERS =1.

"展示加密后信息
PERFORMshow_dataUSINGlf_output.
SKIP.

CLEARlv_input_x.
CLEARlt_recipient_list.
ls_recipient_list-id ='CN=user1'."一般为证书域名
ls_recipient_list-profile ='/tmp/rsa/user1.pse'.
APPENDls_recipient_listTOlt_recipient_list.

"解密
CALLFUNCTION'SSFW_KRN_DEVELOPE'
EXPORTING
    str_format ='PKCS1-V1.5'
    ostr_enveloped_data =lf_output
*b_outdec =''
IMPORTING
    ostr_output_data =lv_input_x
    crc =lv_crc
TABLES
    recipient =lt_recipient_list
EXCEPTIONS
    ssf_krn_error =1
    ssf_krn_noop =2
    ssf_krn_nomemory =3
    ssf_krn_opinv =4
    ssf_krn_nossflib =5
    ssf_krn_recipient_error =6
    ssf_krn_input_data_error =7
    ssf_krn_invalid_par =8
    ssf_krn_invalid_parlen =9
    ssf_fb_input_parameter_error =10
    OTHERS =11.

"根据UTF-8格式转为string类型数据
lv_input =cl_bcs_convert=>xstring_to_string(iv_xstr =lv_input_xiv_cp ='4110').

WRITE:/lv_input.

FORM show_data USING data_x TYPE xstring.
DATA:data_lenTYPEi,
      i1TYPEiVALUE0,
      i2TYPEiVALUE32.
data_len =xstrlen(data_x).
WHILE(i1<data_len).
    i2 =nmin(val1 =i2
               val2 =data_len).
    WRITE:/data_x+i1(i2).
    i1 =i1+32.
ENDWHILE.
ENDFORM.四、简述调用API过程

使用HTTP方式调用银行API
DATA: lv_output         TYPE xstring,
      lv_input_x      TYPE xstring,
      lv_input          TYPE string,
      lt_recipient_list TYPE STANDARD TABLE OF ssfinfo,
      ls_recipient_list LIKE LINE OF lt_recipient_list,
      lv_crc            TYPE ssfparms-ssfcrc.

DATA: lf_input_data    TYPE xstring,
          lf_signed_data   TYPE xstring,
          ls_signer      TYPE ssfinfo,          "ssfinfoext is tested by CL_SMIME
          lt_signer      TYPE TABLE OF ssfinfo, "ssfinfoext is tested by CL_SMIME
          lf_crc         TYPE ssfreturn,
          lf_signer_name   TYPE string,
          lf_chain_dataTYPExstring,
          lf_output_dataTYPExstring,
          lf_inputv_dataTYPExstring,
          ls_certificateTYPEssfcertlin,
          lt_certificatesTYPETABLEOFssfcertlin,
          lf_subject(256)TYPEc.

"原文
lv_input ='一段需要处理的报文'.
CALLFUNCTION'SCMS_STRING_TO_XSTRING'
EXPORTING
    text =lv_input
IMPORTING
    buffer =lv_input_x.

"签名
ls_signer-id ='CN=user1'."一般为证书域名
ls_signer-profile ='/tmp/rsa/user1.pse'.
APPENDls_signerTOlt_signer.

CALLFUNCTION'SSFW_KRN_SIGN'
      EXPORTING
      ssftoolkit ='SAPSECULIB'
      str_format ='PKCS1-V1.5'
      b_inc_certs =''
      b_detached ='X'
      b_inenc =''
      str_hashalg ='SHA256'"'SHA1'
      str_chainfmt =''
      ostr_input_data =lv_input_x
      IMPORTING
      ostr_signed_data =lf_signed_data
      str_signer_name =lf_signer_name
*ostr_signer_keyid =
      ostr_chain_data =lf_chain_data
      crc =lf_crc
      TABLES
      signer =lt_signer
      EXCEPTIONS
      ssf_krn_error =1
      ssf_krn_noop =2
      ssf_krn_nomemory =3
      ssf_krn_opinv =4
      ssf_krn_nossflib =5
      ssf_krn_signer_list_error =6
      ssf_krn_input_data_error =7
      ssf_krn_invalid_par =8
      ssf_krn_invalid_parlen =9
      ssf_fb_input_parameter_error =10
      OTHERS =11.

PERFORMshow_dataUSINGlf_signed_data.
SKIP.

lf_inputv_data =lv_input_x.
"验签
CLEARlt_signer.
*verifysignature
    CALLFUNCTION'SSFW_KRN_VERIFY'
      EXPORTING
      ssftoolkit ='SAPSECULIB'
      str_format ='PKCS1-V1.5'
      b_inc_certs =''
      b_inenc =''
      b_outdec =''
      str_pab ='/tmp/rsa/user1.pse'
*str_pab_password =
      ostr_signed_data =lf_signed_data
      ostr_input_data =lf_inputv_data
      str_hashalg ='SHA256'"'SHA1'
      str_chainfmt =''
*ostr_chain_data =''
      str_signer_name =lf_signer_name
*ostr_signer_keyid =
      crl_profile =''
      IMPORTING
      ostr_output_data =lf_output_data
      crc =lf_crc
      TABLES
      signer_result_list =lt_signer
      certificatelist =lt_certificates
      EXCEPTIONS
      ssf_krn_error =1
      ssf_krn_noop =2
      ssf_krn_nomemory =3
      ssf_krn_opinv =4
      ssf_krn_nossflib =5
      ssf_krn_input_data_error =6
      ssf_krn_invalid_par =7
      ssf_krn_invalid_parlen =8
      ssf_fb_input_parameter_error =9
      OTHERS =10.
IFsy-subrc<>0.
*Implementsuitableerrorhandlinghere
WRITE:/sy-subrc.
ENDIF.


lv_input =cl_bcs_convert=>xstring_to_string(iv_xstr =lf_output_dataiv_cp ='4110').

WRITE:/lv_input.


FORM show_data USING data_x TYPE xstring.
DATA:data_lenTYPEi
      ,i1TYPEiVALUE0
      ,i2TYPEiVALUE32.
data_len =xstrlen(data_x).
WHILE(i1<data_len).
    i2 =nmin(val1 =i2
               val2 =data_len).
    WRITE:/data_x+i1(i2).
    i1 =i1+32.
ENDWHILE.
ENDFORM.根据上述签名之后,得到签名字符串拼接到发送报文中
https://img2022.cnblogs.com/blog/1225252/202206/1225252-20220613162642898-1875059560.png
 发送数据并获得返回消息即可
DATA:lv_input_x      TYPE xstring,
      lv_data TYPE string,
      lv_xdata TYPE xstring,
      lv_input          TYPE string,
      lf_signed_data   TYPE xstring,
      lf_signer_name   TYPE string,
      lf_chain_data    TYPE xstring,
      lf_output_data   TYPE xstring,
      ls_signer      TYPE ssfinfo,          "ssfinfoext is tested by CL_SMIME
      lt_signer      TYPE TABLE OF ssfinfo, "ssfinfoext is tested by CL_SMIME
      lt_certificatesTYPE TABLE OF ssfcertlin,
      lf_crc         TYPE ssfreturn.

DATA: lv_base64    TYPE string,
      lv_pubkey    TYPE xstring,
      lv_pubbase64 TYPE string,
      lv_str       TYPE string.
<br>"签名模板
lv_data = 'json字符串签名模板'.
lv_xdata = cl_abap_codepage=>convert_to( source   = lv_data
                                       codepage = 'UTF-8' ).

"签名
lv_input = 'g0r+iYM0FYAHworrKa+XzL/4FO/ci+S0HZr1pJFAf1/Dtkr+pnpFUWM'
          && 'zf3oHBeJDL3rcCgCqzUOYhpss3MKtOAR/rttdu8a5FQ1G456uYF7D5r'.

CALL FUNCTION 'SCMS_BASE64_DECODE_STR'
EXPORTING
    input= lv_input
*   UNESCAPE       = 'X'
IMPORTING
    output = lv_input_x
EXCEPTIONS
    failed = 1
    OTHERS = 2.

"公钥
lv_pubbase64 = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwFgHD4kzEVPdOj0'
            && 'YCX+zp5r6R52MY0O7BsTCLT7aHaxsANsvI9ABGx3OaTVlPB59M6GPb'.

CALL FUNCTION 'SCMS_BASE64_DECODE_STR'
EXPORTING
    input= lv_pubbase64
*   UNESCAPE       = 'X'
IMPORTING
    output = lv_pubkey
EXCEPTIONS
    failed = 1
    OTHERS = 2.

" 模数
lv_str = lv_pubkey.
DATA(length) = strlen( lv_str ).
IF length > 514." 2048位密钥
DATA(pos) = length - 10 - 514.
lv_str = lv_str+pos(514).
ELSEIF length > 256." 1024位密钥
pos = length - 10 - 256.
lv_str = lv_str+pos(256).
ENDIF.

" 函数使用密钥格式
lv_str = 'R:m=' && lv_str && ':e=010001:'.
lv_pubkey = cl_bcs_convert=>string_to_xstring( lv_str ).

CALL FUNCTION 'SSFW_KRN_VERIFY'
      EXPORTING
      ssftoolkit                   = 'SAPSECULIB'
      str_format                   = 'PKCS1-V1.5'
      b_inc_certs                  = ''
      b_inenc                      = ''
      b_outdec                     = ''
      str_pab                      = '<no_certificate_check>'
*       str_pab_password             =
      ostr_signed_data             = lv_input_x
      ostr_input_data            = lv_xdata
      str_hashalg                  = 'SHA1'
      str_chainfmt               = 'KEYVALUE'
      ostr_chain_data            = lv_pubkey
*       ostr_signer_keyid            =
      crl_profile                  = ''
      IMPORTING
      ostr_output_data             = lf_output_data
      crc                        = lf_crc
      TABLES
      signer_result_list         = lt_signer
      certificatelist            = lt_certificates
      EXCEPTIONS
      ssf_krn_error                = 1
      ssf_krn_noop               = 2
      ssf_krn_nomemory             = 3
      ssf_krn_opinv                = 4
      ssf_krn_nossflib             = 5
      ssf_krn_input_data_error   = 6
      ssf_krn_invalid_par          = 7
      ssf_krn_invalid_parlen       = 8
      ssf_fb_input_parameter_error = 9
      OTHERS                     = 10.
IF sy-subrc <> 0.
* Implement suitable error handling here
WRITE:/ sy-subrc.
ENDIF.
WRITE:/ lf_crc.
lv_input = cl_bcs_convert=>xstring_to_string( iv_xstr =lf_output_data iv_cp = '4110' ).

WRITE:/ lv_input.调用时报错
"创建HTTP对象
CALL METHOD cl_http_client=>create_by_url
    EXPORTING
      url    = ls_ghinfo-zurl
    IMPORTING
      client = lo_http_client.

lo_http_client->propertytype_redirect = lo_http_client->co_disabled .

CALL METHOD lo_http_client->request->set_header_field
    EXPORTING
      name= '~request_method'
      value = 'POST'.               "

CALL METHOD lo_http_client->request->set_header_field
    EXPORTING
      name= '~request_protocol'
      value = 'HTTP/1.1'.

CALL METHOD lo_http_client->request->set_header_field
    EXPORTING
      name= 'Content-Type'
      value = 'application/x-www-form-urlencoded; charset=UTF-8'. 这是因为调用HTTPS地址,没有将网页证书导入到SAP系统。可以在浏览器中下载对应地址的证书,导入SAP系统即可
https://img2022.cnblogs.com/blog/1225252/202206/1225252-20220614143335326-812041709.png
五、致谢

这是一篇站在前人肩膀上完成的博客,各位前辈的资料,给予了本人极大的帮助,尤其感谢CSDN博主​​Fireworks_me​​对我疑惑的耐心解答,非常感谢!
参考文档:
​​https://blogs.sap.com/2021/04/13/rsa-encryption-in-abap/ ​
​​https://blog.csdn.net/xiefireworks/article/details/124809161?spm=1001.2014.3001.5501 ​​
​​https://blog.csdn.net/somehow1002/article/details/117092352 ​​​
​​​https://blog.51cto.com/wushank/1915795​​​
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: ABAP RSA方式调用银行API