一、RSA简介
RSA是非对称加密的一种。
对称加密算法在加密和解密时使用的是同一个秘钥;
非对称加密算法需要一对密钥来加密解密,这两个密钥是公开密钥(public key,简称公钥)和私有密钥(private key,简称私钥)。一个加密,一个解密,由双方各保留一个进行操作。这样,在不传输秘钥的情况下,双方可以针对信息进行加解密,避免了直接传输秘钥可能导致的安全问题。
二、RSA加解密与签名验签
一般来说,有两种场景:加密解密和签名验签
加密解密:使用公钥加密,私钥解密
签名验签:使用私钥加密(签名),公钥解密(验签)
例如:B生成一对密钥,向A提供公钥,B保留私钥
加密:防止信息泄露
当A系统传输数据给B系统,担心报文明文传输会导致信息泄露,则可使用公钥对报文进行加密,以防传输过程中信息泄露。B接收加密报文,通过私钥进行解密
签名:防止信息篡改
当B接收后返回消息给A,担心返回消息被修改,A接收到错误消息,则可使用秘钥进行签名,并将签名和返回报文一起发送给A。A通过公钥进行验签,发现签名解析后和返回报文数据一致,证明报文没有被中间拦截篡改
三、代码实现
1、证书加密解密与签名验签
使用秘钥生成PSE证书方式进行加密解密与签名验签
生成一对密钥后,将私钥文件RSA.key上传到SAP服务器,前后需要加标注,否则不能正常使用

通过命令生成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.
复制代码 根据上述签名之后,得到签名字符串拼接到发送报文中

发送数据并获得返回消息即可- 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_certificates TYPE 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系统即可

五、致谢
这是一篇站在前人肩膀上完成的博客,各位前辈的资料,给予了本人极大的帮助,尤其感谢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
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |