Encryption method that works both in ABAP and PHP? - php

Is there is any encryption function that work in SAP and PHP, of course except using BASE64 encode-decode method.
The scenario is
ABAP encrypt string with key.
The string send to PHP.
PHP decrypt the string using key.
Thank you very much for any advise.

Base64 doesn't an encryption method. #Dirk shared a blog post, which has information about cl_sec_sxml_writer class.
If your system hasn't got this class you can use AES library. It has more capable than cl_sec_sxml_writer class. You can use ECB, CBC, PCBC, CFB, OFB, CTR encryption modes and None, PKCS #5, PKCS #7 padding standarts.
Another option is using SSF_KRN_ENVELOPE function for encrypt. It use RSA standart so result may be huge for ofen trasfers. It is using server certificate for encryption, you an check certificate in STRUST t-code. You check SSF01 demo program.

Related

Dart: How to use the `AES-256-CBC` method in encrypt package?

My PHP server uses the encrypt as follows.
openssl_encrypt('data', 'AES-256-CBC', '1234567890123456', 0, '1234567890123456')
the result is adVh7c/vcyascTS0Z669IA==.
My dart server uses encrypt package as follows.
import 'package:encrypt/encrypt.dart' as encrypt;
Encrypter(AES(encryptKey, mode: AESMode.cbc)).encrypt('data', iv: '1234567890123456').base64
final encrypt.Key encryptKey = encrypt.Key.fromUtf8('1234567890123456');
final encrypt.IV encryptIvKey = encrypt.IV.fromUtf8('1234567890123456');
final encrypt.Encrypter encrypter = encrypt.Encrypter(encrypt.AES(encryptKey, mode: encrypt.AESMode.cbc));
print(encrypter.encrypt('data', iv: encryptIvKey).base64);
The result is KQjJ76efmVlgGKDsj6dCog==.
These result values are different.
I saw the cipher method of PHP. If I change the cipher method in the PHP server from
AES-256-CBC
to
aes-128-cbc // or aes-128-cbc-hmac-sha1, aes-128-cbc-hmac-sha256
The result will be KQjJ76efmVlgGKDsj6dCog==. (same as the result from the dart server)
But editing files in the PHP server is the last choice.
What I can do in the dart server to make the result the same as the result from the PHP server (AES-256-CBC method)?
How to use the AES-256-CBC method in encrypt package?
If I must edit files in the PHP server, what method I should use?
The aes-128-cbc, aes-128-cbc-hmac-sha1 and aes-128-cbc-hmac-sha256 give the same result. Or some method better than this and it is available in encrypt package as follows in this image. Suggestion me, please.
The summary from the comment in my post by #Topaco.
The aes-256-cbc cipher method requires a 32 bytes key.
Use the key with a string length of 32 or use the padRight(32, '\x00') function.
example:
final encrypt.Key encryptKey = encrypt.Key.fromUtf8('1234567890123456'.padRight(32, '\x00'));
Regarding aes-128-cbc, aes-128-cbc-hmac-sha1 and aes-128-cbc-hmac-sha256: Apply aes-128-cbc(ref)

How to decrypt a symmetrically encrypted OpenPGP message using PHP?

I have an OpenPGP message which looks something like this given to me in a file:
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.9 (MingW32)
jA0EAgMCtCzaGHIQXY9g0sBnAeDOQ9GuVA/uICuP+7Z2dnjNCLgRN0J/TzJs1qcW
aJYBTkH5KQCClCxjwTYbHZCox1sENfIS+KxpCKJQqAX3SNEFm0ORNE6RNwEgb1Zj
uOdIw8auxUsjmQKFLAcZIPKjBjyJqSQVfmEoteVn1n+pwm8RdIZevCHwLF2URStB
nBVuycaxcaxcaxcxccxcxacqweqweqwe123fsMqQPaTusOBGpEQrWC9jArtvYEUpY
aNF6BfQ0y2CYrZrmzRoQnmtnVu10PagEuWmVxCucyhVwlthVgN0iBog9jhjliQkc
rrDTupqB4IimMEjElGUHtkuvrCQ0jQnOHEAJmmefMDH0NkYKGd5Ngt21I5ge5tob
/uBjHKMxjNgg1nWfg6Lz4jqoKe/EweuEeg==
=+N9N
-----END PGP MESSAGE-----
and was given a 15 character passphrase to decrypt it, I suppose. But I really don't have any idea to decrypt the file using PHP. I take a look at PHP's GnuPG manual page and under the gnugpg_decrypt() example it gives this code:
$res = gnupg_init();
gnupg_adddecryptkey($res,"8660281B6051D071D94B5B230549F9DC851566DC","test");
$plain = gnupg_decrypt($res,$encrypted_text);
echo $plain;
So taking a look at this function gnupg_adddecryptkey, it mentioned I need a fingerprint. What is that actually? And where can I get it?
The fingerprint is a hash sum calculated on the public key and some meta data like key creation time. It is also returned after importing a key through gnupg_import as fingerprint attribute.
This is for public/private key cryptography, which you're seemingly not using: when encrypting with a passphrase, you're omitting the public/private key cryptography part and directly use symmetric encryption for the message, with a session key (sometimes also called cipher block or symmetric key) derived from your passphrase.
Symmetric encryption is not supported by PHP's GnuPG module. There are no functions to perform symmetric decryption, and this limitation is also described in the module's source documentation:
This class provides an object oriented interface to GNU Privacy Guard (GPG).
Though GPG can support symmetric-key cryptography, this class is intended only to facilitate public-key cryptography.
You will have to perform decryption manually by calling gpg. An example command line would be
gpg --symmetric --decrypt [file]
(alternatively, you can also provide the input through STDIN). For handing over the passphrase, have a look at GnuPG's --passphrase... options:
--passphrase-fd n
Read the passphrase from file descriptor n. Only the first line will be read from file descriptor n. If you use 0 for n, the passphrase will be read from STDIN. This can
only be used if only one passphrase is supplied.
--passphrase-file file
Read the passphrase from file file. Only the first line will be read from file file. This can only be used if only one passphrase is supplied. Obviously, a passphrase
stored in a file is of questionable security if other users can read this file. Don't use this option if you can avoid it.
--passphrase string
Use string as the passphrase. This can only be used if only one passphrase is supplied. Obviously, this is of very questionable security on a multi-user system. Don't use
this option if you can avoid it.
Be aware that all other users of a computer can read all other user's command line arguments, so especially for shared hosting platforms, --passphrase is a definite no-go.
This answer is compatible with not just PHP, but GnuGPG in general. To summarize Jens Erat's answer and adding the encryption step for anyone else who comes across this question, here's a solution, assuming a file exists called passwords.txt:
// encrypt
gpg --output passwords.gpg --symmetric passwords.txt
// decrypt
gpg —decrypt passwords.gpg

Making RSA encryption compatible in Python (PyCrypto) and PHP (OpenSSL)

I am migrating an entire PHP API, and while I used PyCrypto before, I am not sure how to translate the following encryption call, since I need the exact same result. The PHP call is:
define('KEY', "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC81t5iu5C0JxYq5/XNPiD5ol3Z
w8rw3LtFIUm7y3m8o8wv5qVnzGh6XwQ8LWypdkbBDKWZZrAUd3lybZOP7/82Nb1/
noYj8ixVRdbnYtbsSAbu9PxjB7a/7LCGKsugLkou74PJDadQweM88kzQOx/kzAyV
bS9gCCVUguHcq2vRRQIDAQAB
-----END PUBLIC KEY-----");
$cypher = "";
$result = openssl_public_encrypt($plain, $cypher, KEY, OPENSSL_PKCS1_PADDING);
echo bin2hex($cypher);
Assuming everything goes right, this prints the content from $cypher, passed to hexadecimal. For a sample input "azzzzzzzzzzzzdfdf" I get something like: "2281aeebc1166cdfb2f17a0a0775d927ca5a9ad999bae0e4954f58bd8082fdf7efe1fd284876530341f714456d7eb8cd44c57b20ab27029b84d5dc77a674bede3fe9065282931404286082e9df8607bdcff0818b90324dfee7d76b566d0f99bebc5cc913372c276ba373712128f1bcc226b59367cff93f7cdd6dbde25b366863".
I must assume this value as right, since the code was taken from an existing API I am migrating. However, trying the same with PyCrypto (yes, I am migrating the API to be available in Python), I use the following code:
def bin2hex(s):
return "".join([hex(ord(c))[2:].zfill(2) for c in s])
KEY = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC81t5iu5C0JxYq5/XNPiD5ol3Z
w8rw3LtFIUm7y3m8o8wv5qVnzGh6XwQ8LWypdkbBDKWZZrAUd3lybZOP7/82Nb1/
noYj8ixVRdbnYtbsSAbu9PxjB7a/7LCGKsugLkou74PJDadQweM88kzQOx/kzAyV
bS9gCCVUguHcq2vRRQIDAQAB
-----END PUBLIC KEY-----"""
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA
encrypter = PKCS1_v1_5.new(RSA.importKey(KEY))
print bin2hex(encrypter.encrypt("azzzzzzzzzzzzdfdf"));
While I expect the same value be returned and printed, the value finally is "3dd94ffabd01bb0e94010c0fedbcd4eb648f12e5d9e6d934b77ae86f76681d8a1b790cad9fddf6e6720415b4d645e525c33c402fa9778739b8e461790387e9508f7158a5fdc5723f5fc26d166b11a00759f0e0ee3ba6719a2e7c6b918f66e1311d1fff878ee2ca8762e1d6120f1e9585a76cdc7719ca20129ae76182b4277170".
Using PKCS1_OAEP outputs "290f60f37088c2cb46ae9221b01ff46a463f270ef7cf70bbea49de0b5ae43aec34a0eb46e694cf22f689eb77e808c590fdc30eda09f9d3f3cb8c15e0505bf5a984c2a121bc9fa83c6b5ccf50235f072467b4ae9cdf0f0ee2e486626ffa62ad1aa715fbe29e8afe4ceab3ca5a5df4c1dc75d7f258285d7ff1f4f2b4dcb7a8413a".
It is easy to tell that I must fix my python code. How can I fix my python code so it returns the exact same result as the given PHP call?
Your code is fine. PKCS#1 v1.5 padding in pyCrypto is randomized (source). So the encryption will always be different even if you use the same key and plaintext. This is a desirable property.
If you want to check compatibility between pyCrypto and PHP's OpenSSL extension, then you would need to encrypt in one, decrypt in the other and check that you got what you expected.
PKCS#1 v1.5 padding should not be used nowadays, because there are efficient attacks against it. OAEP is a much better alternative.
I've struggled with the same problem for quite long but finally managed to solve this.
The main issue was setting proper SHA hashes, in case of PHP's openssl_public_encrypt() it should be SHA1.
Here's the code for openssl_public_encrypt() with OPENSSL_PKCS1_OAEP_PADDING:
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
def encrypt_key(message):
with open('public_key', 'rb') as key_file:
pub_key = key_file.read()
public_key = load_pem_public_key(pub_key, default_backend())
ciphertext = public_key.encrypt(
message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA1()),
algorithm=hashes.SHA1(),
label=None
)
)
return ciphertext
basically a copy of cryptography.io documentation regarding RSA.

AES 256 and Base64 Encrypted string works on iOS 8 but truncated on iOS 7

One of my app needs to download a database with the content encrypted in AES 256. So I've used on server side phpAES to encode the strings in AES CBC with an IV.
On the iOS side I'm using FBEncryptor to decrypt the string.
This is the code on the server side:
$aes = new AES($key, "CBC", $IV);
$crypt = $aes->encrypt($string);
$b64_crypt = base64_encode($crypt);
On the iOS side I'm doing this:
NSString* decrypt = [FBEncryptorAES decryptBase64String:b64_crypt keyString:key iv:iv];
Actually everythings works fine on iOS 8. The problem is on iOS 7 where the decoded string is truncated at random length.
Thoughts?
Don't use phpAES. You're shooting yourself in the foot with an enormous cannon.
From their page:
The free version only supports ECB mode, and is useful for encrypting/decrypting credit card numbers.
This is incredibly wrong and misleading. ECB mode is not suitable for any purpose except as a building block for other modes of operation. You want an AEAD mode; or, failing that, CBC or CTR with HMAC-SHA2 and a CSPRNG-derived IV/nonce. Using unauthenticated encryption is a very bad idea.
For interoperability with iOS, you should use libsodium.
Objective-C: SodiumObjc or NAChloride
PHP: libsodium-php (also available in PECL)
If you cannot use libsodium, your best bet is OpenSSL and explicitly not mcrypt, and a compatible interface on the iOS side.
All currently supported versions (5.4+) of PHP expose openssl_encrypt() and openssl_decrypt() which allow fast and secure AES-CBC and AES-CTR encryption. However, you should consider using a library that implements these functions for you instead of writing them yourself.
The truncation could be the result of incompatible padding.
phpAES uses non-standard null padding similar to mcrypt, this is unfortunate since the standard for padding is PKCS#7. It is unfortunate that one has to read the code to find that out. It is important to supply a 256-bit (32-byte) key since that sets the key size for the algorithm.
FBEncryptor only supports PKCS#7 padding.
So, these two methods are incompatible.
One solution is to add PKCS#7 padding to the string in php prior to calling phpAES which will not then add the null padding. Then FBEncryptor will be compatible with the encrypted data.
PKCS#7 padding always adds padding. The padding is a series by bytes with the value of the number of padding bytes added. The length of the padding is the block_size - (length(data) % block_size.
For AES where the block is is 16-bytes (and hoping the php is valid, it had been a while):
$pad_count = 16 - (strlen($data) % 16);
$data .= str_repeat(chr($pad_count), $pad_count);
Please add to the question working example keys, iv clear data and encrypted data as hex dumps.

Verify and decrypt signature generated with a pvk.key and BouncyCastle crypto apis

I have an applet that uses a "foo.key" file and a string password to generate a privateKey object, using BouncyCastle apis. Then a signature is created using this privateKey object and a string such as "MYNAMEHERE". All I know is that the algorythm used to generate this signature is RSA.
What I want to do is to decrypt (or verify) this signature in PHP. I have both files publicKey (file.cer) and privateKey (file.key) that where used to generate the privateKey object in Java.
Im trying using the openssl_verify functions in PHP, passing the values:
openssl_verify("MYNAMEHERE", $signature, "file.cer"), where $signature contains the String representation of the signature object generated in Java: new String (signature).
I dont know if this process is correct to verify the signature, or what kind of encoding/decoding process i have to do before using this function.
I hope somebody points me the right direction!
Thanks in advance!
You haven't given enough information, such as the actual signature or how it is encoded. Normally RSA means RSA in PKCS#1 1.5 mode using SHA-1 (Google it) which is more or less the default signature generation/verification algorithm in use today. In that case, the verify should proceed as you've described. The password is not needed anymore, it might just be used to decrypt the private key. You can still use the private key to see if an sign in PHP/openssl does create the same data. If not, a different hash or PKCS#1 v2.1 signature may have been used.

Categories