• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Rob Spoor
  • Tim Cooke
  • Junilu Lacar
Sheriffs:
  • Henry Wong
  • Liutauras Vilda
  • Jeanne Boyarsky
Saloon Keepers:
  • Jesse Silverman
  • Tim Holloway
  • Stephan van Hulst
  • Tim Moores
  • Carey Brown
Bartenders:
  • Al Hobbs
  • Mikalai Zaikin
  • Piet Souris

AES encryption using provided password

 
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

I am attempting to encrypt a string for passing to SagePay, but so far my attempts are rejected by SagePay saying that the encryption method I have used is not supported.

Their doc says: This string should be encrypted using the AES/CBC/PCKS#5 algorithm and the pre-registered Encryption password, then subsequently Base64 encoded to allow safe transport in an HTML form.

The password they provide looks a bit like this: 8JQc4w5MUsZ47Z8z

Here is some code I cobbled together to encrypt my plainTextString using my passwordString
I didn't know how to convert the password they provide to a SecretKey used by Cipher, so there are guesses in there.

byte[] byteDataToEncrypt = plainTextString.getBytes();
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

SecureRandom rand = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[16];
rand.nextBytes(salt);
PBEKeySpec keySpec = new PBEKeySpec(passwordString.toCharArray(), salt, 65536, 256);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKey key = (PBEKey) factory.generateSecret(keySpec);
SecretKey secretKey = new SecretKeySpec(key.getEncoded(), "AES");

aesCipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] byteCipherText = aesCipher.doFinal(byteDataToEncrypt);
crypt = new BASE64Encoder().encode(byteCipherText);
System.out.println("Cipher Text generated using AES is " + crypt);

Have SagePay provided enough info for me to achieve the encryption; they have basically just told me that I must be doing it wrong and they can't help and certainly wouldn't comment on any code! They do provide a Java api, but then the bit that does the encryption is as they put it "locked down" so they refuse to provide a class/method in the API to do the encryption/decryption for me!

Many thanks to anyone who can help.

John
 
Bartender
Posts: 1166
17
Netbeans IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
As you seem to appreciate, just saying that one should use AES/CBC/PCKS#5 is not enough. You will also need from them

a) the algorithm used to convert the Encryption password to a 16 byte AES key,
b) the IV used to initialise the CBC.

You have assumed that the key is generated using PBE based on PBKDF2WithHmacSHA1. This may or may not be correct but even if it is you need to know the salt and the iteration count. The salt can't be a random value as you have assumed!

If the SagePay key looks like 8JQc4w5MUsZ47Z8z (I assume that is not the real key) and if it is exactly 16 characters long then there is a chance that the key bytes are actually just the ASCII bytes of 8JQc4w5MUsZ47Z8z and can be obtained using "8JQc4w5MUsZ47Z8z".getBytes("ASCII") .

I'm betting that SagePay assume an IV of 16 bytes of zero (this is a very common failing) which introduces a small security weakness. It means that one will be able to tell if two encrypted messages longer than 16 byte start with the same content! This weakness would be removed if the IV is a random value and shipped with the ciphertext but I bet that SagePay don't use this approach.

In your position I would first try using "8JQc4w5MUsZ47Z8z".getBytes("ASCII") as the key with an IV of 16 bytes of zero. If this fails I would put in a call to SagePay and ask them to come clean.

Note that if SagePay do use "8JQc4w5MUsZ47Z8z".getBytes("ASCII") as the key then there effective key length is significantly shorter than 128 bits; it will be more like 95 bits (approx 16*log2(62)) .
 
John Pollard
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Richard, I really appreciate your detailed reply. I have passed the questions to SagePay, though from past experience I don't hold out hopes of a quick / detailed reply. You mentioned something to try below, but without the salt it sounds like trying anything would be futile? This suggests to me that they want clients to use their own code to do the encryption, but they have hidden the encryption bit of their own API / not documented it / will not answer questions about it, perhaps in their eyes for security reasons. They instead provided a J2EE sample application, but I don't use a J2EE app framework.
John
 
Richard Tookey
Bartender
Posts: 1166
17
Netbeans IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You don't need a salt or iteration count if the key is just the ASCII bytes of the password and the IV is 16 bytes of zero! You can get rid of all your current PBE key generation and just use the bytes of the passphrase. The change is very very simple -
 
John Pollard
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ok, I tried that and passed the iv from your code in

cipher.init(Cipher.ENCRYPT_MODE, key, iv);

Though the same error from SagePay that the encryption method is not supported. I will await their response, thanks again.
 
John Pollard
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The response from SagePay is once again predictable; they say the only information they provide is the password! They seem to view their system API and documentation as not really theirs, or at least not something their customer service team can touch with a barge pole. Hopeless!
 
Richard Tookey
Bartender
Posts: 1166
17
Netbeans IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
So how do other people access SagePay? Do SagePay provide a Java module that you can use? If not do they provide a perl or c++ or Python libraries?

The only interface to SagePay I can find is a Web based username and password page. Are you trying to emulate that?
 
John Pollard
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The do provide code here including Java http://www.sagepay.co.uk/support/find-an-integration-document/form-integration
The Java integration kit is however actually a sample J2EE application which I am not familiar with. I was unable to isolate the bit where the encryption/decryption is actually done as much of the download does not provide source, the source code is just the J2EE sample application bits from what I can see. There is probably a simple answer lurking in there somewhere. I thought I had found it when I located a byte[] aesEncrypted = CryptographyHelper.AESEncrypt(detail, "ISO-8859-1", webSite.encryptionPassword()); method, but the end result was the same error once they receive the encrypted data. SagePay are unable to say whether I located the correct class / method or not or exactly how to use it.
 
John Pollard
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I think this contains clues and relates to SagePay, but is C-sharp rather than Java: http://stackoverflow.com/questions/17511279/c-sharp-aes-decryption
 
Richard Tookey
Bartender
Posts: 1166
17
Netbeans IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
There is some Java source. Maybe not the whole Java API source but certainly not just example source. A quick looks at the source and documentation make me think that the encryption is the least of your worries! If you are not going to learn to use SagePay API then there is a whole protocol to implement. No small task. I think you are going to have to bite the bullet and spend significant time learning to use the SagePay API. J2EE ain't that hard and from a quick look at the examples the API seem easy enough to understand !

Best of luck.
 
Richard Tookey
Bartender
Posts: 1166
17
Netbeans IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

John Pollard wrote:I think this contains clues and relates to SagePay, but is C-sharp rather than Java: http://stackoverflow.com/questions/17511279/c-sharp-aes-decryption



There is an implication in that C# that SagePay use the same bytes for the IV as are used in the password! You can but try it!
 
John Pollard
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Richard, our software actually integrates with SagePay already using their previously supported encryption method of Xor, which is no longer supported. The API is simple enough, the data is all there, the only bit that needs upgrading is the encryption/decryption method. Unfortunately they hide that bit away as far as I can make out. From the link I posted above, someone knows a bit more than SagePay are telling me about their encryption process! Thanks, John
 
John Pollard
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I was quite hopeful of the keyBytes and ivBytes being the same, but still not going through. I notice the code also mentions Rijndael which I tried in place of AES for both the SecretKeySpec construction and the Cipher.getInstance() but nether worked. I can't help thinking I am getting close. I'm suspicious about some "@" at the beginning which I saw in some other code somewhere else.
 
John Pollard
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This also shows similar: http://stackoverflow.com/questions/13360079/php-mcrypt-equivalent-for-sagepay-on-a-windows-server
Again indicating that sagepay uses the same string for key and iv
Also there is that "@" being added to the front of the result.
I tried adding the "@" and the error changed…no longer saying the encryption was wrong, but complaining about a missing currency field in the unencrypted data, which I know is present.
What about the Rijndael and 128 translated to Java?

//** AES encryption, CBC blocking with PKCS5 padding then HEX encoding - DEFAULT **

//** use initialization vector (IV) set from $strEncryptionPassword
$strIV = $strEncryptionPassword;

//** add PKCS5 padding to the text to be encypted
$strIn = addPKCS5Padding($strIn);

//** perform encryption with PHP's MCRYPT module
$strCrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $strEncryptionPassword, $strIn, MCRYPT_MODE_CBC, $strIV);

//** perform hex encoding and return
return "@" . bin2hex($strCrypt);
 
Richard Tookey
Bartender
Posts: 1166
17
Netbeans IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

John Pollard wrote:

What about the Rijndael and 128 translated to Java?;



When the tender went out for AES there were several proposed encryption algorithms and the winner was Rijndael limited to 128 bit block size. So AES is Rijndael with block size of 128 bits.

The chances of the decryption working using the wrong key and IV and then providing a meaningful decrypted output are are effectively zero so the fact that you are getting an error message saying that a currently is missing is encouraging. It means you have probably decrypted correctly. You say the currency field is not missing but unless the decryption software is rubbish I would doubt this; you have only a 1 in 255 chance of the decrypted PKCS5 padding being valid for an arbitrary key and/or IV.
 
John Pollard
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
SagePay have confirmed that they can't decrypt at their end still, so the change in error message is just a bit confusing; they are looking for "Currency" in a garbage string and not finding it. I will post back if/when I can resolve this.
 
John Pollard
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Finally resolved, the following worked:



The change that appeared to get me over he line was to use Hex.encodeHexString() instead of Base64.encodeBase64(), which I spotted in another forum posting.

Even easier, I was then able to go back to using the SagePay API with that step added:


Richard, you have been a huge help to me. If you have anything for me to pass on to SagePay, please do let me know! I don't understand security and encryption, but I don't see that I should need to; I just need a working and documented API provided by SagePay.
Thanks
John
 
Richard Tookey
Bartender
Posts: 1166
17
Netbeans IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Interesting. Two different passwords and an API that does it all for you in 2 lines !

Well done.
 
I need a new interior decorator. This tiny ad just painted every room in my house purple.
Thread Boost feature
https://coderanch.com/t/674455/Thread-Boost-feature
reply
    Bookmark Topic Watch Topic
  • New Topic