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]