Skip to Content
Technical Articles
Author's profile photo Former Member

RSA Encryption in ABAP

Recently I stumbled across a lot of unanswered questions about RSA encryption. Here I will try to provides some examples how to use public/private key encryption in ABAP. All the overhead like certificates, trust, revocation and key generation will not be touched here. The keys will be generated with openssl.

Example 1 – Using own RSA implementation  in ABAP.

 

RSA encryption is quite simple. All you need is integer arithmetic – mainly modular exponentiation. The only problem is, the integers involved are longer than ABAP and most other languages can handle by default. Luckily this problem is solved by Harry Boeck with the class Z04_BIGINTX which can be found here (excellent work).

Generating the RSA key.

First make a working directory and cd to it.

mkdir -p /tmp/rsa
cd /tmp/rsa

Generate 2048 bit RSA key.

/tmp/rsa > openssl genrsa -out rsa.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
.....................................................................+++++
.......+++++
e is 65537 (0x010001)

Print out the key with the public and private components in plain text. We need only the modulus, the publicExponent and the privateExponent.

/tmp/rsa > openssl pkey -in rsa.key -text
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDiBbntt4wk807Q
Bzh0gdwwXFyxe1/a41dDZeekgxC5p649B1pT6Ft7P6eSmZqDdZ6t04JpzAdyHjzj
2DMPt6VpAkXyaQSXLHd7dKWYnw2b/akWptd761zx9oIY1tHz0y4VbfkX0yt7FwvP
jUK6XfpcyYymJ1KMmG/UhsIENLxhaU56/gnKdl01XTcKe+JkBpv02dpw+bw6BE34
21FXFmSpoduAHA8/lm+9U6PqdvxU6IDB16n5X74IyUCTQsMW7XQgaw3cqVWTYigU
sZFbHPEddfkCZDNfSodmRd+WZTuCRjD6+K/9+K1j7Kk4a2LMC7r0bPOIYcrW+0VC
+ykiz8QTAgMBAAECggEBAL27/tt+FEhEcymQliS/in6SWkGnBs1xwKRUXEMuvxCK
oWqbzIjZakopIlufVCT8zMqw3i4/1xRGK+k8aYjNKi7feKZI4FCjRF2/iu92vW7w
XkwknIlrB6gavhVp5+9dnLbijZMhcsOukfyWYaifEXdovggQxGw/3siyoxXyyxyd
PSB1Wf+LdZ1EOTaEfk3+lgEpEUzdFTNEC/jwrQJiXzSB+nP5bB0Az3kMcbhxwa01
hAUylXCNtnrRJv0sMvQJOy59gBjiPn3GW62t8Kf/km3IlDRKE7h9xYECafQabaXR
0q6swX09YpdKKBEHYLE9ArpamJtJYPtlA2XSvsfBqkECgYEA84Bt20EpBPldrUFN
GLb7qKNPawRbMff204xx7OtzHD77Th6hcvaXU0C/D4c+DMZNQ/2M4xbLoZWPTOnK
BxOhpbZMH4prxLA4U/6TDQwo9F3kW/1zPcYKfxOgW6tlVHWnLR4Kd1+W7ygNOhjV
El6lWwi008547z05w5ZQ2T+U3OECgYEA7Z+fO6ZWIRqHJq1MCzStTtS+hGkwJArj
DGy8AbvGV7LScmH31sxRJqZp6jHMOICBjgwAPN0VE5eq+xUcPs0p5/seTy/MzSbf
uRG+A//PIG/yUVuOV6nuCYKsY2v2oTUF+v8HGMkfa7WkEhD5S5lZ+oA8gVMXQ4Ey
J235xfPu63MCgYEA4qA+HljX14RK1kw3d/Ad6ocMDDsCsU/qDlvhUDKWcMyBUeSa
OIgesOJKsCYb7wHEuanKrTPzE5FBzMCuQcXYpYUz9gr7YBTuZ+ZAcF1H5J9aQO9z
iSO/cyQOFCNB7MiPbiNOdGmn7S/ml5KzBCTIWyCQQ60fyvG9yDYnSvqtDqECgYBk
29Cxd9us916QKxRQ2U4KXMB04VTep4RRnMF8FuCMDsnGZRDWKijzt8TS88oT3W+g
BDYBn3E3vLOFGSPBAEIeRfdKcyaBmVNycTZu6iBXS0zV/X+AdA8mGEHlfUjUifX8
4Ex517wvcoyuYmf+D5wieFW2KreAHpFULRjMTcqGQwKBgQCMrLoC1dasdvcQ/d9r
sd1AlGjSjoVhGeb19NYQMdOxx29vExP45ClSmnTCTZIZFVpeXHQ4X3ALq2uK4bQp
Cyqrz+4TRLY9e9qgTqNsWkhyke9YSAYNxCb17ZXf7rtHgTJeGbnDvrKC8xa2EvgR
sZknhXCegj6UBsECwPBrYZoDag==
-----END PRIVATE KEY-----
RSA Private-Key: (2048 bit, 2 primes)
modulus:
    00:e2:05:b9:ed:b7:8c:24:f3:4e:d0:07:38:74:81:
    dc:30:5c:5c:b1:7b:5f:da:e3:57:43:65:e7:a4:83:
    10:b9:a7:ae:3d:07:5a:53:e8:5b:7b:3f:a7:92:99:
    9a:83:75:9e:ad:d3:82:69:cc:07:72:1e:3c:e3:d8:
    33:0f:b7:a5:69:02:45:f2:69:04:97:2c:77:7b:74:
    a5:98:9f:0d:9b:fd:a9:16:a6:d7:7b:eb:5c:f1:f6:
    82:18:d6:d1:f3:d3:2e:15:6d:f9:17:d3:2b:7b:17:
    0b:cf:8d:42:ba:5d:fa:5c:c9:8c:a6:27:52:8c:98:
    6f:d4:86:c2:04:34:bc:61:69:4e:7a:fe:09:ca:76:
    5d:35:5d:37:0a:7b:e2:64:06:9b:f4:d9:da:70:f9:
    bc:3a:04:4d:f8:db:51:57:16:64:a9:a1:db:80:1c:
    0f:3f:96:6f:bd:53:a3:ea:76:fc:54:e8:80:c1:d7:
    a9:f9:5f:be:08:c9:40:93:42:c3:16:ed:74:20:6b:
    0d:dc:a9:55:93:62:28:14:b1:91:5b:1c:f1:1d:75:
    f9:02:64:33:5f:4a:87:66:45:df:96:65:3b:82:46:
    30:fa:f8:af:fd:f8:ad:63:ec:a9:38:6b:62:cc:0b:
    ba:f4:6c:f3:88:61:ca:d6:fb:45:42:fb:29:22:cf:
    c4:13
publicExponent: 65537 (0x10001)
privateExponent:
    00:bd:bb:fe:db:7e:14:48:44:73:29:90:96:24:bf:
    8a:7e:92:5a:41:a7:06:cd:71:c0:a4:54:5c:43:2e:
    bf:10:8a:a1:6a:9b:cc:88:d9:6a:4a:29:22:5b:9f:
    54:24:fc:cc:ca:b0:de:2e:3f:d7:14:46:2b:e9:3c:
    69:88:cd:2a:2e:df:78:a6:48:e0:50:a3:44:5d:bf:
    8a:ef:76:bd:6e:f0:5e:4c:24:9c:89:6b:07:a8:1a:
    be:15:69:e7:ef:5d:9c:b6:e2:8d:93:21:72:c3:ae:
    91:fc:96:61:a8:9f:11:77:68:be:08:10:c4:6c:3f:
    de:c8:b2:a3:15:f2:cb:1c:9d:3d:20:75:59:ff:8b:
    75:9d:44:39:36:84:7e:4d:fe:96:01:29:11:4c:dd:
    15:33:44:0b:f8:f0:ad:02:62:5f:34:81:fa:73:f9:
    6c:1d:00:cf:79:0c:71:b8:71:c1:ad:35:84:05:32:
    95:70:8d:b6:7a:d1:26:fd:2c:32:f4:09:3b:2e:7d:
    80:18:e2:3e:7d:c6:5b:ad:ad:f0:a7:ff:92:6d:c8:
    94:34:4a:13:b8:7d:c5:81:02:69:f4:1a:6d:a5:d1:
    d2:ae:ac:c1:7d:3d:62:97:4a:28:11:07:60:b1:3d:
    02:ba:5a:98:9b:49:60:fb:65:03:65:d2:be:c7:c1:
    aa:41
.
.
.

Now with the key and the Z04_BIGINTX class we are ready to write our program.

ABAP program

In the following program we are encrypting with the public key and signing with the private key this message ‘Thirty-two bytes secret message!’. The results are displayed on the screen. They are saved in the same folder where we generated the key to check them outside of SAP. Signing normally involves hashing the message and signing the hash, bus as our message is small enough we skip hashing and sign the message itself. As Proof of Concept should be sufficient.

The actual work is just a couple of lines.

For encryption:

msg_encr_bi = msg_plain_bi->powmod( x = publicExponent
                                    m = pub_modulus_bi ).

and for signing:

msg_encr_bi = msg_plain_bi->powmod( x = priv_exponent_bi
                                    m = pub_modulus_bi ).

The rest is converting from hex to decimal and back.

REPORT Z_RSA.

data: bi1     type ref to z04_BigIntX,
      bi2     type ref to z04_BigIntX,
      bi256   type ref to z04_BigIntX,

      s  type string,

      i1 type I,
      i2 type I,
      i3 type I value 0,

      x1 type X,

      publicExponent   type ref to z04_BigIntX,

      pub_modulus_s    type string,
      pub_modulus_x    type xstring,
      pub_modulus_bi   type ref to z04_BigIntX,

      priv_exponent_s  type string,
      priv_exponent_x  type xstring,
      priv_exponent_bi type ref to z04_BigIntX,

      msg_text         type string,
      msg_plain_bi     type ref to z04_BigIntX,
      msg_encr_bi      type ref to z04_BigIntX,
      msg_encr_x       type xstring,
      msg_sign_x       type xstring,

      pkcs_rnd         type xstring,
      pkcs_ff_s        type string,
      pkcs_ff_x        type xstring,
      pkcs_head_sign   type xstring value '0001',
      pkcs_head_encr   type xstring value '0002',
      pkcs_zero        type xstring value '00',
      pkcs_one         type xstring value '01',
      msg_xstr         type xstring,
      msg_xstr_e       type xstring,
      msg_xstr_s       type xstring,

      msg_file_name    type string value '/tmp/rsa/encrypted_msg',
      msg_file_name_s  type string value '/tmp/rsa/signed_msg'.

create object msg_plain_bi.
create object bi1.
create object bi2.
create object bi256.
create object publicExponent.
create object pub_modulus_bi.
create object priv_exponent_bi.
create object msg_encr_bi.


DATA: T1 TYPE I, T2 TYPE I, T3 TYPE I.

bi256->seti( 256 ).

*---------------------
* PREPARE THE KEY
*---------------------

" public exponent
publicExponent->setstr( '65537' ).

" private exponent
CONCATENATE
  '00:bd:bb:fe:db:7e:14:48:44:73:29:90:96:24:bf:'
  '8a:7e:92:5a:41:a7:06:cd:71:c0:a4:54:5c:43:2e:'
  'bf:10:8a:a1:6a:9b:cc:88:d9:6a:4a:29:22:5b:9f:'
  '54:24:fc:cc:ca:b0:de:2e:3f:d7:14:46:2b:e9:3c:'
  '69:88:cd:2a:2e:df:78:a6:48:e0:50:a3:44:5d:bf:'
  '8a:ef:76:bd:6e:f0:5e:4c:24:9c:89:6b:07:a8:1a:'
  'be:15:69:e7:ef:5d:9c:b6:e2:8d:93:21:72:c3:ae:'
  '91:fc:96:61:a8:9f:11:77:68:be:08:10:c4:6c:3f:'
  'de:c8:b2:a3:15:f2:cb:1c:9d:3d:20:75:59:ff:8b:'
  '75:9d:44:39:36:84:7e:4d:fe:96:01:29:11:4c:dd:'
  '15:33:44:0b:f8:f0:ad:02:62:5f:34:81:fa:73:f9:'
  '6c:1d:00:cf:79:0c:71:b8:71:c1:ad:35:84:05:32:'
  '95:70:8d:b6:7a:d1:26:fd:2c:32:f4:09:3b:2e:7d:'
  '80:18:e2:3e:7d:c6:5b:ad:ad:f0:a7:ff:92:6d:c8:'
  '94:34:4a:13:b8:7d:c5:81:02:69:f4:1a:6d:a5:d1:'
  'd2:ae:ac:c1:7d:3d:62:97:4a:28:11:07:60:b1:3d:'
  '02:ba:5a:98:9b:49:60:fb:65:03:65:d2:be:c7:c1:'
  'aa:41'
into priv_exponent_s.
replace ALL OCCURRENCES OF REGEX '(:)' in priv_exponent_s with ''.
TRANSLATE priv_exponent_s TO UPPER CASE.
priv_exponent_x = priv_exponent_s.
" Convert the modulus from HEX to DEC
bi2->seti( 1 ).
i1 = xstrlen( priv_exponent_x ).
WHILE ( i1 > 0 ).
  i1 = i1 - 1.
  i2 = priv_exponent_x+i1(1).
  bi1->seti( i2 ).
  bi1->mul( bi2 ).
  bi2->mul( bi256 ).
  priv_exponent_bi = priv_exponent_bi->add( bi1 ).
ENDWHILE.

" public key
CONCATENATE
  '00:e2:05:b9:ed:b7:8c:24:f3:4e:d0:07:38:74:81:'
  'dc:30:5c:5c:b1:7b:5f:da:e3:57:43:65:e7:a4:83:'
  '10:b9:a7:ae:3d:07:5a:53:e8:5b:7b:3f:a7:92:99:'
  '9a:83:75:9e:ad:d3:82:69:cc:07:72:1e:3c:e3:d8:'
  '33:0f:b7:a5:69:02:45:f2:69:04:97:2c:77:7b:74:'
  'a5:98:9f:0d:9b:fd:a9:16:a6:d7:7b:eb:5c:f1:f6:'
  '82:18:d6:d1:f3:d3:2e:15:6d:f9:17:d3:2b:7b:17:'
  '0b:cf:8d:42:ba:5d:fa:5c:c9:8c:a6:27:52:8c:98:'
  '6f:d4:86:c2:04:34:bc:61:69:4e:7a:fe:09:ca:76:'
  '5d:35:5d:37:0a:7b:e2:64:06:9b:f4:d9:da:70:f9:'
  'bc:3a:04:4d:f8:db:51:57:16:64:a9:a1:db:80:1c:'
  '0f:3f:96:6f:bd:53:a3:ea:76:fc:54:e8:80:c1:d7:'
  'a9:f9:5f:be:08:c9:40:93:42:c3:16:ed:74:20:6b:'
  '0d:dc:a9:55:93:62:28:14:b1:91:5b:1c:f1:1d:75:'
  'f9:02:64:33:5f:4a:87:66:45:df:96:65:3b:82:46:'
  '30:fa:f8:af:fd:f8:ad:63:ec:a9:38:6b:62:cc:0b:'
  'ba:f4:6c:f3:88:61:ca:d6:fb:45:42:fb:29:22:cf:'
  'c4:13'
into pub_modulus_s.
replace ALL OCCURRENCES OF REGEX '(:)' in pub_modulus_s with ''.
TRANSLATE pub_modulus_s TO UPPER CASE.
pub_modulus_x = pub_modulus_s.
" Convert the modulus from HEX to DEC
bi2->seti( 1 ).
i1 = xstrlen( pub_modulus_x ).
WHILE ( i1 > 0 ).
  i1 = i1 - 1.
  i2 = pub_modulus_x+i1(1).
  bi1->seti( i2 ).
  bi1->mul( bi2 ).
  bi2->mul( bi256 ).
  pub_modulus_bi = pub_modulus_bi->add( bi1 ).
ENDWHILE.

*---------------------
* END PREPARE THE KEY
*---------------------

msg_text = 'Thirty-two bytes secret message!'.
write: / 'Plain message:'.
write: / msg_text.
SKIP.

*---------------------
* START ENCRYPTION
*---------------------

CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
  EXPORTING
    text = msg_text
  IMPORTING
    buffer = msg_xstr.

write: / 'Plain message in HEX:'.
PERFORM SHOW_DATA USING msg_xstr.
SKIP.

i1 = 256 - 3 - xstrlen( msg_xstr ).

CALL FUNCTION 'GENERATE_SEC_RANDOM'
  EXPORTING
    length = i1
  IMPORTING
    random = pkcs_rnd
  EXCEPTIONS
    INVALID_LENGTH = 1
    NO_MEMORY = 2
    INTERNAL_ERROR = 3.

  do i1 TIMES.
    CONCATENATE 'FF' pkcs_ff_s INTO pkcs_ff_s.
  enddo.
  pkcs_ff_x = pkcs_ff_s.

REPLACE ALL OCCURRENCES OF pkcs_zero in pkcs_rnd with pkcs_one IN BYTE MODE.

CONCATENATE
 pkcs_head_encr
 pkcs_rnd
 pkcs_zero
 msg_xstr
into msg_xstr_e in byte mode.

write: / 'Plain message PKCS1-V1.5 padded for encryption in HEX:'.
PERFORM SHOW_DATA USING msg_xstr_e.
SKIP.

" Convert the padded plain text message from HEX to DEC
i1 = xstrlen( msg_xstr_e ).
bi2->seti( 1 ).
WHILE ( i1 > 0 ).
  i1 = i1 - 1.
  i2 = msg_xstr_e+i1(1).
  bi1->seti( i2 ).
  bi1->mul( bi2 ).
  bi2->mul( bi256 ).
  msg_plain_bi = msg_plain_bi->add( bi1 ).
ENDWHILE.

" Encrypt the message
GET RUN TIME FIELD T1.
msg_encr_bi = msg_plain_bi->powmod( x = publicExponent
                                    m = pub_modulus_bi ).
GET RUN TIME FIELD T2.
T3 = T2 - T1.
write: / 'Encryption time:', T3.

" Convert the encrypted message from DEC to HEX
WHILE ( s <> '0' ).
  i1 = bi2->setobj( msg_encr_bi )->mod( bi256 )->getstr( 0 ) + i3.
  if i1 = 256.
     i3 = 1.
  else.
     i3 = 0.
  endif.
  x1 = i1.
  s = msg_encr_bi->div( bi256 )->getstr( 0 ).
  CONCATENATE x1 msg_encr_x INTO msg_encr_x IN BYTE MODE.
ENDWHILE.

" output encrypted message
OPEN DATASET msg_file_name FOR OUTPUT IN BINARY MODE.
TRANSFER msg_encr_x TO msg_file_name.
CLOSE DATASET msg_file_name.

write: / 'RSA encrypted message:'.
PERFORM SHOW_DATA USING msg_encr_x.
SKIP.

*---------------------
* END ENCRYPTION
*---------------------


*---------------------
* START SIGNING
*---------------------
" Message PKCS#1 padding for signing
CONCATENATE
 pkcs_head_sign
 pkcs_ff_x
 pkcs_zero
 msg_xstr
into msg_xstr_s in byte mode.
write: / 'Plain message PKCS1-V1.5 padded for signing in HEX:'.
PERFORM SHOW_DATA USING msg_xstr_s.
SKIP.

" Convert the padded plain text message from HEX to DEC
msg_plain_bi->seti( 0 ).
i1 = xstrlen( msg_xstr_s ).
bi2->seti( 1 ).
WHILE ( i1 > 0 ).
  i1 = i1 - 1.
  i2 = msg_xstr_s+i1(1).
  bi1->seti( i2 ).
  bi1->mul( bi2 ).
  bi2->mul( bi256 ).
  msg_plain_bi = msg_plain_bi->add( bi1 ).
ENDWHILE.

" Sign the message
GET RUN TIME FIELD T1.
msg_encr_bi = msg_plain_bi->powmod( x = priv_exponent_bi
                                    m = pub_modulus_bi ).
GET RUN TIME FIELD T2.
i1 = T2 - T1.
write: / 'Signing time:', i1.

s = ''.
msg_sign_x = ''.

" Convert the encrypted message from DEC to HEX
WHILE ( s <> '0' ).
  i1 = bi2->setobj( msg_encr_bi )->mod( bi256 )->getstr( 0 ) + i3.
  if i1 = 256.
     i3 = 1.
  else.
     i3 = 0.
  endif.
  x1 = i1.
  s = msg_encr_bi->div( bi256 )->getstr( 0 ).
  CONCATENATE x1 msg_sign_x INTO msg_sign_x IN BYTE MODE.
ENDWHILE.

" Output signed message
OPEN DATASET msg_file_name_s FOR OUTPUT IN BINARY MODE.
TRANSFER msg_sign_x TO msg_file_name_s.
CLOSE DATASET msg_file_name_s.

write: / 'RSA signed message:'.
PERFORM SHOW_DATA USING msg_sign_x.

*---------------------
* END SIGNING
*---------------------

FORM SHOW_DATA USING  data_x TYPE xstring.
  DATA: data_len TYPE I
      , i1       TYPE I value 0
      , i2       TYPE I value 32.
  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.

Here the output.

We see encryption with the public exponent, which is almost always 65537, takes ~0.2 seconds where signing with the private exponent takes 30 seconds.

Let’s now check the results with openssl.

Decrypt.

/tmp/rsa >xxd encrypted_msg
00000000: dd64 ff4c f19e 6274 b3fd aa8b ecc2 9fe0  .d.L..bt........
00000010: 6d87 760f 1239 d01f 81ce e53b 3587 f601  m.v..9.....;5...
00000020: 8e03 4099 a582 bbdd e45b 7cf7 be79 76b9  ..@......[|..yv.
00000030: 7068 3cd5 2b72 a7d6 2c51 e805 36d3 3eb8  ph<.+r..,Q..6.>.
00000040: c11c 4584 01f3 3bfd d265 1bf7 aff1 d97a  ..E...;..e.....z
00000050: aded 0b4a b59d 3c3c 4675 e38d 8409 aedc  ...J..<<Fu......
00000060: 1242 b562 5ced 9662 c9f3 5974 4cc3 3227  .B.b\..b..YtL.2'
00000070: b750 6cea e244 892b 873f 32e7 c4fd 4f78  .Pl..D.+.?2...Ox
00000080: 6a5e 7063 d0fe c5ef 9219 8549 b025 47c9  j^pc.......I.%G.
00000090: 0b3a 5598 d780 aab4 ab5a 6bb0 8ba5 f822  .:U......Zk...."
000000a0: 735f 2b43 68e6 5630 9c90 1712 6196 6d06  s_+Ch.V0....a.m.
000000b0: e2fc 87c1 db42 554f 3688 929a 6550 5173  .....BUO6...ePQs
000000c0: b951 30f6 ca5b a60a 2cc7 5710 915a 2809  .Q0..[..,.W..Z(.
000000d0: c6d8 60ba 3eac bcc1 9814 cc6a e777 757f  ..`.>......j.wu.
000000e0: 44ae ce00 3869 a275 4c4b 3f8e e5e2 eb67  D...8i.uLK?....g
000000f0: 34ac 13cb f89e 5edc 9d67 d5e8 704e d9c6  4.....^..g..pN..
/tmp/rsa >
/tmp/rsa >openssl rsautl -decrypt -in encrypted_msg -inkey rsa.key | xxd
00000000: 5468 6972 7479 2d74 776f 2062 7974 6573  Thirty-two bytes
00000010: 2073 6563 7265 7420 6d65 7373 6167 6521   secret message!

Adding -raw to openssl displays the whole message

/tmp/rsa >openssl rsautl -decrypt -in encrypted_msg -inkey rsa.key -raw | xxd
00000000: 0002 4316 8cf2 e289 8dc4 67cf be1b f547  ..C.......g....G
00000010: ae0b b98b 8ef8 79ba 9b98 ac20 3660 d6ac  ......y.... 6`..
00000020: 3330 e613 752c a9ab 3f88 368b 223b 050b  30..u,..?.6.";..
00000030: b79d 40c2 2ef9 9de9 e363 10d1 199b 97f0  ..@......c......
00000040: 33da b96d e3fc 62d6 06c4 ebb5 3ee2 b823  3..m..b.....>..#
00000050: 4f22 d924 ac1d dd89 0215 889f 4c1f 9364  O".$........L..d
00000060: 1220 81bd 21d7 1dd2 280e d74a 4024 99ae  . ..!...(..J@$..
00000070: a8ed 3fad 30aa e281 db4c 5454 c237 9bc0  ..?.0....LTT.7..
00000080: 9338 2a39 197b 9972 4c11 b260 7f31 e407  .8*9.{.rL..`.1..
00000090: 81ea 2be7 a9da 336b 6b66 8bde 1774 3bd0  ..+...3kkf...t;.
000000a0: 0ccd 3b93 983c 1c51 b32d a31b 06f6 533e  ..;..<.Q.-....S>
000000b0: 144a 1c2a f32d 875f 4873 8b41 dcc7 8b18  .J.*.-._Hs.A....
000000c0: 40e4 4414 bd7e c49a 5282 b165 3698 fdf6  @.D..~..R..e6...
000000d0: 9e20 b83b 3185 c7ee 962a 9bb5 f173 8900  . .;1....*...s..
000000e0: 5468 6972 7479 2d74 776f 2062 7974 6573  Thirty-two bytes
000000f0: 2073 6563 7265 7420 6d65 7373 6167 6521   secret message!

Verify.

/tmp/rsa >xxd signed_msg
00000000: d540 f2b5 1e7e bb83 aa6e d099 1ad6 ee1e  .@...~...n......
00000010: ccdb ffaf e579 0e98 323e b055 7164 4b71  .....y..2>.UqdKq
00000020: a71c 0e6e 5e74 3fdb c914 97ac e063 8ece  ...n^t?......c..
00000030: 086e d8ac fad9 14a7 7f47 bd34 22a9 d0ab  .n.......G.4"...
00000040: 73e7 80fc 65af fbd7 d3df 7672 1d31 88e7  s...e.....vr.1..
00000050: b489 311c eb36 25bf 3e8b 4efb b97c df96  ..1..6%.>.N..|..
00000060: 5440 165b a820 514d 9649 531f 402c 5767  T@.[. QM.IS.@,Wg
00000070: 508c adeb 1954 e14f e2ce d64e ba30 0c4a  P....T.O...N.0.J
00000080: aeca 0927 7823 9bc6 0083 99f7 e605 ae9d  ...'x#..........
00000090: 2cd9 205e 41f4 1587 5b3f 1574 047d 42b3  ,. ^A...[?.t.}B.
000000a0: 6e5a a74b cfaa fde5 4d09 26f9 82ca f1b5  nZ.K....M.&.....
000000b0: 9299 f2df 7444 472d 1554 3378 c544 7f20  ....tDG-.T3x.D.
000000c0: b6b0 80be a241 2d24 c561 da69 522d 86db  .....A-$.a.iR-..
000000d0: 2388 cbe5 15fe 9967 3bbd 36f5 5a70 8a05  #......g;.6.Zp..
000000e0: a30c 2c89 2f05 b470 15d3 482f e53b 947a  ..,./..p..H/.;.z
000000f0: c7f5 feba bd41 a877 750e c9f8 cb7a c7b1  .....A.wu....z..
/tmp/rsa >
/tmp/rsa >openssl rsautl -verify -in signed_msg -inkey rsa.key | xxd
00000000: 5468 6972 7479 2d74 776f 2062 7974 6573  Thirty-two bytes
00000010: 2073 6563 7265 7420 6d65 7373 6167 6521   secret message!
/tmp/rsa >
/tmp/rsa >openssl rsautl -verify -in signed_msg -inkey rsa.key -raw | xxd
00000000: 0001 ffff ffff ffff ffff ffff ffff ffff  ................
00000010: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000020: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000030: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000040: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000050: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000060: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000070: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000080: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000090: ffff ffff ffff ffff ffff ffff ffff ffff  ................
000000a0: ffff ffff ffff ffff ffff ffff ffff ffff  ................
000000b0: ffff ffff ffff ffff ffff ffff ffff ffff  ................
000000c0: ffff ffff ffff ffff ffff ffff ffff ffff  ................
000000d0: ffff ffff ffff ffff ffff ffff ffff ff00  ................
000000e0: 5468 6972 7479 2d74 776f 2062 7974 6573  Thirty-two bytes
000000f0: 2073 6563 7265 7420 6d65 7373 6167 6521   secret message!

 

Example 2 – Using CommonCryptoLib

 

All RSA stuff can be done easily with Function group SSFW – SSF Functions for Web Services Security. All except what you can get with the (-raw) switch in openssl. For example if you want to use non-standard padding, bit this should be rarely the case.

To make my life easy I will create a PSE from the key used in Example 1 and use that PSE.

In production you may consider to do it right through SSFA, STRUST and SSF_GET_PARAMETER.

 

Create the PSE.

/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

Move to ABAP

REPORT Z_RSA_CCL.

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: T1 TYPE I, T2 TYPE I, T3 TYPE I.


lf_plain_input = 'Thirty-two bytes secret message.'.
CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
  EXPORTING
      text = lf_plain_input
  IMPORTING
    buffer = lf_plain_input_x.

DATA: it_recipient_list   TYPE STANDARD TABLE OF ssfinfo,
      wa_recipient_list   LIKE LINE OF it_recipient_list.
wa_recipient_list-id = 'CN=user1'.
APPEND wa_recipient_list TO it_recipient_list.

GET RUN TIME FIELD T1.
CALL FUNCTION '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.
GET RUN TIME FIELD T2.
T3 = T2 - T1.
write: / 'Encryption time:', T3.

msg_file_name = '/tmp/rsa/ccl_encrypted_msg'.
OPEN DATASET msg_file_name FOR OUTPUT IN BINARY MODE.
TRANSFER lf_output TO msg_file_name.
CLOSE DATASET msg_file_name.

write: / 'RSA CCL encrypted message:'.
PERFORM SHOW_DATA USING lf_output.
skip.

DATA: lf_signer          TYPE ssfinfo.
DATA: lt_signer TYPE STANDARD TABLE OF ssfinfo." WITH HEADER LINE.
lf_signer-id = 'CN=user1'.
lf_signer-profile = '/tmp/rsa/user1.pse'.
APPEND lf_signer TO lt_signer.

GET RUN TIME FIELD T1.
CALL FUNCTION 'SSFW_KRN_SIGN'
  EXPORTING
    str_format       = 'PKCS1-V1.5'
    str_chainfmt     = 'X509v3'
    STR_HASHALG      = 'SHA256'
    ostr_input_data  = lf_plain_input_x
  IMPORTING
    ostr_signed_data = lf_output
  TABLES
    signer           = lt_signer
  EXCEPTIONS
    OTHERS =              1.
GET RUN TIME FIELD T2.
T3 = T2 - T1.
write: / 'Signing time:', T3.


msg_file_name = '/tmp/rsa/ccl_signed_msg'.
OPEN DATASET msg_file_name FOR OUTPUT IN BINARY MODE.
TRANSFER lf_output TO msg_file_name.
CLOSE DATASET msg_file_name.

write: / 'RSA CCL signed message:'.
PERFORM SHOW_DATA USING lf_output.


FORM SHOW_DATA USING  data_x TYPE xstring.
  DATA: data_len TYPE I
      , i1       TYPE I value 0
      , i2       TYPE I value 32.
  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.

After execution.

Check it with openssl again

Decrypt.

/tmp/rsa > xxd ccl_encrypted_msg
00000000: 3c5b 4c97 0c5c 0e68 1f84 7ced 4f01 e11c  <[L..\.h..|.O...
00000010: 3bce b761 a03e ad15 2f9d 5836 f187 1e44  ;..a.>../.X6...D
00000020: ca71 7cfb 84ef 0b2d 2203 fe6a 502e f065  .q|....-"..jP..e
00000030: 9790 c4cd 8164 912b 8b13 926b 4537 b953  .....d.+...kE7.S
00000040: a3d1 1f15 0919 ccf4 d3af 9e2b 6bfb 7e61  ...........+k.~a
00000050: 1f25 6d70 c9d5 c48e b38b aa6c 5300 d22b  .%mp.......lS..+
00000060: aaac e4b5 6dc5 cb66 39a2 86e2 a41d 96ab  ....m..f9.......
00000070: 6901 ade9 8a17 74df 8237 a963 73a4 4da9  i.....t..7.cs.M.
00000080: bf13 7be2 704a fc8c 8889 1fad 279e 6397  ..{.pJ......'.c.
00000090: 2d13 d0d1 22a2 c0de 8c72 b12f bd90 31ec  -..."....r./..1.
000000a0: ef98 0a7f f971 5f71 4a9f 4060 0715 4c40  .....q_qJ.@`..L@
000000b0: 1397 09c8 333b df8a 3243 2db3 c276 d875  ....3;..2C-..v.u
000000c0: 6cad 5dcb af41 f00c 2cad 4053 da72 158c  l.]..A..,.@S.r..
000000d0: ac67 52ad 6940 8049 4c3c 727a a19e a513  .gR.i@.IL<rz....
000000e0: 716d a4eb 0826 07c4 1624 307f 68d6 3014  qm...&...$0.h.0.
000000f0: 43ec 2cb8 ea44 2868 1a24 e1aa 594b e646  C.,..D(h.$..YK.F

/tmp/rsa > openssl rsautl -decrypt -in ccl_encrypted_msg -inkey rsa.key | xxd
00000000: 5468 6972 7479 2d74 776f 2062 7974 6573  Thirty-two bytes
00000010: 2073 6563 7265 7420 6d65 7373 6167 652e   secret message.

/tmp/rsa > openssl rsautl -decrypt -in ccl_encrypted_msg -inkey rsa.key -raw | xxd
00000000: 0002 da46 9aee 3bb8 53e7 9ecf 99a0 0a60  ...F..;.S......`
00000010: e8cc 89e5 56ad 4c10 d2a5 6a62 6612 068e  ....V.L...jbf...
00000020: 9f7a e956 4325 0b32 7e75 457a ac75 639c  .z.VC%.2~uEz.uc.
00000030: 64a5 17b7 5c1c 721a d2d3 1a2b 1770 0a73  d...\.r....+.p.s
00000040: ccec 5802 66b7 d2e3 2f96 11bd 6708 2d3d  ..X.f.../...g.-=
00000050: 298c 76ce 02f9 7b84 4a36 911b 81ad d047  ).v...{.J6.....G
00000060: 5452 6e64 2d0d f55a c048 9f13 2aef ff70  TRnd-..Z.H..*..p
00000070: ff2d 7c5d 0162 a8d0 82d2 5c64 bf3c e380  .-|].b....\d.<..
00000080: b93d 4d98 a1b6 164c 8ded 016d ad94 9fd2  .=M....L...m....
00000090: 7632 e64c 080f 7728 5817 0f50 1d9c cfd3  v2.L..w(X..P....
000000a0: f67e 5ccb eafb 9cc9 9916 4bd4 c64e 1494  .~\.......K..N..
000000b0: f47f e38e 33f4 2121 91df d9f9 7233 f182  ....3.!!....r3..
000000c0: 2008 bb21 654d 0fd3 482d da42 8cfb b4c1   ..!eM..H-.B....
000000d0: a267 78ae e55e cde5 1f8d e3e6 d5df 1000  .gx..^..........
000000e0: 5468 6972 7479 2d74 776f 2062 7974 6573  Thirty-two bytes
000000f0: 2073 6563 7265 7420 6d65 7373 6167 652e   secret message.

Verify.

/tmp/rsa > xxd ccl_signed_msg
00000000: 9e8f 2678 2ed6 3d6d ae74 16f6 4101 75ed  ..&x..=m.t..A.u.
00000010: 3fd0 d962 7f2b 7d46 f3b7 8097 7411 37f3  ?..b.+}F....t.7.
00000020: 89c6 e3fc 81b7 93a6 7814 020b 9b3a 8ebd  ........x....:..
00000030: 9e9f 3549 e521 a7ff 27ef aef5 10f5 dada  ..5I.!..'.......
00000040: e2cb f6b9 8cf4 c663 43f2 98d7 2127 040d  .......cC...!'..
00000050: 6b4e 7c23 bad7 db40 7442 9c4d d6b4 b0f9  kN|#...@tB.M....
00000060: 2e35 5500 1499 c938 536f 6763 99b5 895b  .5U....8Sogc...[
00000070: 2b57 5b81 f757 ffee f7fa dc8c b447 afd8  +W[..W.......G..
00000080: 1630 ac6f 5621 8fc1 c3ab ed7f 1893 3b91  .0.oV!........;.
00000090: 9575 055c 7a9e 6a76 b5ce 000e 5ab2 3eae  .u.\z.jv....Z.>.
000000a0: 5574 2a8e f0fa 3f2e 9897 2c95 4e64 16bc  Ut*...?...,.Nd..
000000b0: 0040 00fd 3202 d458 8c1f 45da 7f1c f238  .@..2..X..E....8
000000c0: 8e68 0dc1 b692 d1bb 48c2 2f0d a429 eaa8  .h......H./..)..
000000d0: b962 05ba 0a7b b246 7719 1406 5649 0681  .b...{.Fw...VI..
000000e0: fae5 dadd 7946 1775 5e2d eff7 2d95 993a  ....yF.u^-..-..:
000000f0: 9a6f 4e7b 0770 b887 b34f 271a 43af 8e68  .oN{.p...O'.C..h

/tmp/rsa > openssl rsautl -verify -in ccl_signed_msg -inkey rsa.key | xxd
00000000: 3031 300d 0609 6086 4801 6503 0402 0105  010...`.H.e.....
00000010: 0004 20c0 4726 d78a 7628 27e3 dffe 9f42  .. .G&..v('....B
00000020: c2fe e624 7a2e 59f7 a0c9 85ef 7728 a5d4  ...$z.Y.....w(..
00000030: a106 8f                                  ...

/tmp/rsa > openssl rsautl -verify -in ccl_signed_msg -inkey rsa.key -raw | xxd
00000000: 0001 ffff ffff ffff ffff ffff ffff ffff  ................
00000010: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000020: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000030: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000040: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000050: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000060: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000070: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000080: ffff ffff ffff ffff ffff ffff ffff ffff  ................
00000090: ffff ffff ffff ffff ffff ffff ffff ffff  ................
000000a0: ffff ffff ffff ffff ffff ffff ffff ffff  ................
000000b0: ffff ffff ffff ffff ffff ffff ffff ffff  ................
000000c0: ffff ffff ffff ffff ffff ffff 0030 3130  .............010
000000d0: 0d06 0960 8648 0165 0304 0201 0500 0420  ...`.H.e.......
000000e0: c047 26d7 8a76 2827 e3df fe9f 42c2 fee6  .G&..v('....B...
000000f0: 247a 2e59 f7a0 c985 ef77 28a5 d4a1 068f  $z.Y.....w(.....

/tmp/rsa > echo -n 'Thirty-two bytes secret message.' | sha256sum
c04726d78a762827e3dffe9f42c2fee6247a2e59f7a0c985ef7728a5d4a1068f  -

Here we see the SHA hash of the message is signed.

 

Conclusion

 

Here we have learned how to RSA encrypt / sign short messages in ABAP using 2 different approaches.

  • The pure ABAP implementation. It is nowhere near in performance (and security) to the CommonCryptoLib. It was fun to do and gives us a better understanding what RSA encryption is.
  • CommonCryptoLib. The examples here are a basic ones. There is a lot more one can do with. Probably for a next blog.

 

Thank you for reading. Please feel free to send me a message or write a comment here.

 

 

Assigned Tags

      31 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Tom Demuyt
      Tom Demuyt

      Would love to see an example with STRUST and a passphrase. Super bad idea to have encryption keys so visible on the file system.

      Author's profile photo Former Member
      Former Member

      Let’s elaborate on this.

      In RSA context encryption is done with public keys, and having other people public keys unprotected is IMHO not such a super bad idea.

      Signing on the other hand is done with private keys and they are well worth to be protected. Putting a passphrase in STRUST seems to be a super cool idea, but it isn't. It is more like locking the door and putting the key under the mat - read cred_v2. Your best option today is LPS (with TPM on Linux, not fallback), which makes decryption offline very difficult

      But if someone else, with not super good intentions, is able to walk on the operating system, your keys, protected or not, are done just the same.

      All in all, you have to protect the visible and the "invisible" keys equally.

      For password exampes look at the standard test report SSF01.

      Author's profile photo Tom Demuyt
      Tom Demuyt

      You show a PSE key on the file system, which contain both the private and public key, still sounds like a super bad idea within the context your provided.

      https://help.sap.com/doc/7b705a6a728810148a4b1a83b0e91070/1511%20000/en-US/frameset.htm?4c61a6c6364012f3e10000000a15822b.html

      If the best option is LPS (with TPM), then I would love to see an example of that 😉

       

      Author's profile photo Former Member
      Former Member

      And in the beginning of the post the private key is posted even more visible. You don't do this normally, either.

      Author's profile photo Lars Hvam
      Lars Hvam

      I have another bigint implementation at https://github.com/larshp/abapPGP/tree/main/src/integer, including extented GCD, Knuth long division, Karatsuba multiplication and Montgomery modular multiplication, probabilistic prime determination 🙂

      Author's profile photo Former Member
      Former Member

      Hi Lars, I was not aware of it. Seems very interesting. It's definitely worth looking deeper into. One can learn a lot. Thanks.

      Author's profile photo Lars Hvam
      Lars Hvam

      Its been some years since I looked at it, but remember that the algorithms were quite fun 🙂

      Author's profile photo Enno Wulff
      Enno Wulff

      You didn't set the word fun in quotation marks... Lars Hvam 😅

      Author's profile photo Former Member
      Former Member

      Just for the record. Today I tried this implementation. While easier to use, it can handle HEX in/out directly, it takes three and a half times longer to sign the message - 108 seconds towards 30 seconds. Tested with modular_pow_montgomery with the progress_indicator disabled.

      Author's profile photo Lars Hvam
      Lars Hvam

      cool, compared to the custom ABAP implementation and/or CommonCryptoLib?

      Author's profile photo Former Member
      Former Member

      To the custom (Z04_BIGINTX->POWMOD). CCL needs 2 thousandth of a second.

      Author's profile photo Albin Ary
      Albin Ary

      Hello Former Member

       

      thanks a lot for sharing this.

       

      I tried following your example and it is working just fine.

      But, when I tried with another PSE (I created it from a pfx file which has Private key and Certificate) it is not doing anything. It executes sucessfully but both messages are empty. Do you have any suggestion?

      Author's profile photo Former Member
      Former Member

      Hi Albin Ary

       

      first I would look in SM21. If there is an error you get no info in ABAP but the problem is traced there.

      Possible error is recipient/signer ID. It has to be the full distinguished name e.g "CN=UserName, O=SAP, C=DE" and not only "CN=UserName"

      Author's profile photo Albin Ary
      Albin Ary

      Thank you for the reply and info.

      And you are right, in SM21 there are errors. I am pasting below together with the codes.

      Unfortunately I do not get it. These are the corresponding codes of the errors.

       

      9 SSF API: Recipient error
      26 SSF signer/recipient list: No certificate
      5 SSF API: Signer error
      22 SSF signer/recipient list: Unknown signer or recipient

       

       

      I get this info for the working pse:

       

      sapgenpse.exe get_my_name -p user1.pse

      Subject : CN=user1
      Issuer : CN=user1
      Serialno : 1D:EB:76:89:23:7E:DC:B3:2C:E3:F7:23:08:BD:98:18:CA:3E:F3:21
      KeyInfo : RSA, 2048-bit
      Validity - NotBefore: Wed Jun 16 11:28:08 2021 (210616102808Z)
      NotAfter : Sat Jun 14 11:28:08 2031 (310614102808Z)
      KeyUsage : none
      ExtKeyUsage : none
      SubjectAltName : none

       

      and this one for mine:

       

      Subject : S=XXX, SN=XXX, CN=XXX, T=XXX, OU=XXX, O=XXX, L=XXX
      Issuer : CN=XXX, O=XXX, C=XXX
      Serialno : ...........................................................
      KeyInfo : RSA, 2048-bit
      Validity - NotBefore: ........................
      NotAfter : .........................
      KeyUsage : digitalSignature nonRepudiation keyEncipherment dataEncipherment
      ExtKeyUsage : ClientAuthentication Email
      SubjectAltName : none

       

      I have replaced the data with XXX

      For wa_recipient_list-id and lf_signer-id I have used Issuer. Should this be ok?

       

       

       

      Author's profile photo Former Member
      Former Member

      Hi Albin Ary

      "I have used Issuer. Should this be ok?"

      No. Therefore Unknown signer or recipient

      Use Subject.

      Author's profile photo Albin Ary
      Albin Ary

      Thanks a lot. It worked as expected.

      Author's profile photo Albin Ary
      Albin Ary

      Hello again,

      In production you may consider to do it right through SSFA, STRUST and SSF_GET_PARAMETER.

      I am trying to find out how we could do this in a productive system, where we can sue a password protected pse added in STRUST which can be used programmatically.

      As far as I can see the documentation is not that good. Could you please point to some documentation, official or non-official? Thanks

       

      Author's profile photo Former Member
      Former Member

      Hi Albin Ary

      have a look at this post by Wayne Brown.

      Or this question/answer.

      Search the community.

      Ask your Basis colleagues to help you with pass-protecting the PSE.

      Author's profile photo Albin Ary
      Albin Ary

      Thanks a lot!

      Author's profile photo Eik Sunke
      Eik Sunke

      Hi Former Member

      I found your blog while trying to accomplish the following:

      We have a dataset that is signed by a non ABAP application.

      The verification of the signature with JavaScript it is easy to do:

                          window.crypto.subtle.verify(
                              {
                                  name: "RSA-PSS",
                                  saltLength: 32,
                              },
                              this.publicKey,
                              this.stringToArrayBuffer(this.base64ToBinary(parts[1])), // the signature
                              this.stringToArrayBuffer(parts[0])                       // content
                          )

       

      What I would like to do is to use a ABAP class to do the signature validation. I tried some things without success. Do you have a hint for me, how I could accomplish this?

      Thanks in advance,

      Eik

      Author's profile photo Former Member
      Former Member

      Hi Eik Sunke,

       

      there is a Function module SSFW_KRN_VERIFY which should do the trick.

      CommonCryptoLib supports PSS mode, too.

      It will be easier to help, if you share more details what you tried and where you failed.

       

      Regards

      Robert

       

       

      Author's profile photo Eik Sunke
      Eik Sunke

      Hi, thanks for the quick reply.

      I tested that function with no luck. It just does not give me a reply.

      My assumption was that I did not supply proper Parameter. Most likely for str_pab.

      I am using my public key as TYPE ssfpab. But maybe I need to do some adjustments?

      For "ostr_signed_data" I created a xstring (using 'SCMS_STRING_TO_XSTRING') out of my signed data. And I just created a new table (TYPE STANDARD TABLE OF ssfinfo) for signer_result_list

      I do not get any reply.

      Author's profile photo Former Member
      Former Member

      The information is still sparingly provided.

      But, you surely get a reply.

      SM21 is the first place to look at.

      Then are the traces. Increasing the trace level helps, too.

       

      Good luck!

      Author's profile photo Kesinee Iabkongchai
      Kesinee Iabkongchai

      Hi Former Member

      Very nice blog. And have you had a chance to write decryption code in SAP ABAP?

      I have a requirement to decrypt files from Success Factor which are encrypted with PGP public key. And I have to write the ABAP Code to decrypt them before loading them into SAP BPC Model.

      Or if you have any suggestions, it would be really appreciated.

      Sukanya

       

       

      Author's profile photo Former Member
      Former Member

      Hi Kesinee Iabkongchai,

      PGP involves:

      Public-Key Algorithms - for encrypting the session key (RSA,DSA,EC,ECDSA...)
      Symmetric-Key Algorithms  - for encrypting the payload (IDEA, 3DES, Blowfish, AES....)
      Compression Algorithms - for compressing the payload before encryption (ZIP, ZLIB, BZip2)
      Hash Algorithms (MD5, SHA-1 to 512, RIPPE-MD/160)
      Radix-64 (basically Base64 with optional CRC24)

      Depending on which combination of the above the particular PGP is using, it may be possible to decrypt it in ABAP. You have to break the message into corresponding parts and do the decryption step by step.

       

      Author's profile photo Mainak Aich
      Mainak Aich

      Hello Former Member

      It was so informative and neatly explained, thanks so much!

      I had a requirement where I am receiving only a single value of RSA public key from the sender. I am not getting the public exponent and modulus separately. In this case, how can I can break the RSA public key to determine the public exponent and modulus in ABAP? Any suggestion would be helpful.

      Thanks,

      Mainak

      Author's profile photo Former Member
      Former Member

      Hi Mainak,

      getting the modulus and exponent is easy but the ABAP implementation above is hopelessly slow.

      # cat public_key.pem
      -----BEGIN PUBLIC KEY-----
      MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKw3reQ91sdocUK0VCd6AVVa0j3kt1bC
      B4ZX0zLTBYaB8Iv7VmSHu/Q4P/h4zNrjzVXUrAt6ZrKa7wGtT4UiUhUCAwEAAQ==
      -----END PUBLIC KEY-----
      
      # openssl rsa -pubin -in public_key.pem -text -noout
      RSA Public-Key: (512 bit)
      Modulus:
          00:ac:37:ad:e4:3d:d6:c7:68:71:42:b4:54:27:7a:
          01:55:5a:d2:3d:e4:b7:56:c2:07:86:57:d3:32:d3:
          05:86:81:f0:8b:fb:56:64:87:bb:f4:38:3f:f8:78:
          cc:da:e3:cd:55:d4:ac:0b:7a:66:b2:9a:ef:01:ad:
          4f:85:22:52:15
      Exponent: 65537 (0x10001)
      

       

      I would suggest you use CommonCryptoLib (with e.g. SSFW_KRN_VERIFY). You need the public key wrapped in certificate.

      If they don't want (or are not able) to provide it, one can make own cert for this. Have a look here.

       

      Cheers, Robert

       

      Author's profile photo Mainak Aich
      Mainak Aich

      Hello Robert,

      Many thanks for your reply, actually in our case the RSA public key won't be a fixed key meaning it has a validity of 1 day. So everyday I will receive a new RSA pubic key from my sender. So I am looking for an algorithm using which I can derive the modulus and public exponent in my ABAP program.

      So, if I get a RSA public key like below, can you please suggest what should be the algorithm to get the modulus and exponent in ABAP?

      -----BEGIN PUBLIC KEY-----
      MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKw3reQ91sdocUK0VCd6AVVa0j3kt1bC
      B4ZX0zLTBYaB8Iv7VmSHu/Q4P/h4zNrjzVXUrAt6ZrKa7wGtT4UiUhUCAwEAAQ==
      -----END PUBLIC KEY-----

      Thanks,
      Mainak

      Author's profile photo Former Member
      Former Member

      Well, basically the string between -----BEGIN / END PUBLIC KEY----- is the base64 form of the key, which itself is in ASN.1 format. So:

      echo -n "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKw3reQ91sdocUK0VCd6AVVa0j3kt1bCB4ZX0zLTBYaB8Iv7VmSHu/Q4P/h4zNrjzVXUrAt6ZrKa7wGtT4UiUhUCAwEAAQ==" | base64 -d | xxd -g1

      Sounds famillier?

      pub%20key%20as%20hex

      Not aware of standart ABAP, which you can use. Fortunately the base64 decode and the simple ASN.1 excract for the key are easily done.

      Author's profile photo Mainak Aich
      Mainak Aich

      Hi Robert,

      I could also figure out something similar going by the URL https://medium.com/@bn121rajesh/understanding-rsa-public-key-70d900b1033c

      But can you please help me understand what is the starting byte of the modulus? how many header bytes to skip to find the modulus header byte? What is the logic you used to figure out from byte "00 ac..." the modulus is starting? Can you please guide me here.

      If I know the logic of that piece probably I can explore in ABAP to skip those header and trailer bytes in the byte string to derive the modulus and I can assume to pick the last 3 bytes as public exponent.

      Please let me know your thought.

      Thanks,

      Mainak

      Author's profile photo Former Member
      Former Member

      Hello Mainak,

      Proper implementation would be not just to skip the header, but to read and process it according the ASN.1. Check the report ASN1_PARSER. It does not split the BIT STRING, but is a starting point.

      Lazy way is to read it backwards. 3 bytes exponent, 2 bytes overhead, (key_length/8) bytes for the key.

      Either way the leading zero byte plays no role in the math we are doing. 10 / 02 = 5

      Regards, Robert