Skip to Content
Technical Articles

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.

 

 

11 Comments
You must be Logged on to comment or reply to a post.
  • Would love to see an example with STRUST and a passphrase. Super bad idea to have encryption keys so visible on the file system.

    • 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.

      • 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 😉

         

  • /
    🙂