Duplicate Oracle DES encrypting in Java - java

I recently asked a question about Oracle Encryption. Along the way to finding a solution for myself I decided to move the encryption (well, obfuscation) to the application side for certain tasks.
My problem is that the database is already encrypting data a certain way and I need Java code to duplicate that functionality, so that text encrypted by one system can be decrypted by the other and vice versa.
I want the encryption to be compatible with what the DB was already doing but couldn't find the documentation that describes exactly what Oracle is doing. How do I replicate this in Java?
dbms_obfuscation_toolkit.DESEncrypt(
input_string => v_string,
key_string => key_string,
encrypted_string => encrypted_string );
RETURN UTL_RAW.CAST_TO_RAW(encrypted_string);
No matter what I try, it seems as if the Java DES encryption is different than Oracle's.

I found this works:
KeySpec ks = new DESKeySpec(new byte[] {'s','e','c','r','e','t','!','!'});
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
SecretKey sk = skf.generateSecret(ks);
Cipher c = Cipher.getInstance("DES/CBC/NoPadding");
IvParameterSpec ips = new IvParameterSpec(new byte[] {0,0,0,0,0,0,0,0});
c.init(Cipher.ENCRYPT, sk, ips);
// or
c.init(Cipher.DECRYPT, sk, ips);
The missing piece was the Initialization Vector (ips) which must be 8 zeros. When you use null in Java you get something different.

Using Java in the database would have been another approach that would (should!) have guarenteed that the code (and hence results) would be identical.

Related

Bouncy Castle Curve25519 private key from Scrypt output

I am trying to achieve ECIES encryption, for which below code is working.
X9ECParameters ecP = CustomNamedCurves.getByName("curve25519");
ECParameterSpec ecSpec = EC5Util.convertToSpec(ecP);
BigInteger d = new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990");
ECPrivateKeySpec priKeySpec = new ECPrivateKeySpec(
d, // d
ecSpec);
ECPoint Q = new FixedPointCombMultiplier().multiply(params.getG(), d.multiply(BigInteger.valueOf(-1)));
Q = Q.normalize();
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
new ECPoint(Q.getAffineXCoord().toBigInteger(), Q.getAffineYCoord().toBigInteger()), // Q
ecSpec);
KeyFactory factTrial = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
BCECPrivateKey sKey = (BCECPrivateKey) factTrial.generatePrivate(priKeySpec);
PublicKey vKey = factTrial.generatePublic(pubKeySpec);
Cipher c = Cipher.getInstance("ECIESwithAES-CBC",BouncyCastleProvider.PROVIDER_NAME);
byte[] encodeBytes = c.doFinal(data.getBytes());
String encrypt = Base64.getEncoder().encodeToString(encodeBytes);
Cipher c2 = Cipher.getInstance("ECIESwithAES-CBC",BouncyCastleProvider.PROVIDER_NAME);
c2.init(Cipher.DECRYPT_MODE,sKey, c.getParameters());
byte[] decodeBytes = c2.doFinal(encodeBytes);
String deCrypt = new String(decodeBytes,"UTF-8");
Issue is the private key element 'd'. If I try to replace it with output of scrypt hash, private key fails to be converted in PrivateKey instance.
I have gone through net resources https://github.com/bcgit/bc-java/issues/251, https://crypto.stackexchange.com/questions/51703/how-to-convert-from-curve25519-33-byte-to-32-byte-representation, https://crypto.stackexchange.com/questions/72134/raw-curve25519-public-key-points.
Above resources suggest the way Bouncy Castle for Curve25519 interprets private key is different from the ways some internet resource suggest. In post https://crypto.stackexchange.com/questions/51703/how-to-convert-from-curve25519-33-byte-to-32-byte-representation there is mention as follows.
According to the curve25519 paper a x25519 public key can be represented in 32 bytes.
The x25519 library I'm using (bouncycastle) however gives me a 33 byte representation according to this standard.
I am very new to ECC, these resources are confusing me, the difference between lengths, the style of encoding big vs. little.
I have tried libSodium 'crypto_box_easy' and 'crypto_box_open_easy'
via its Java binding and it works all fine. The 32 byte scrypt output
is used by 'crypto_box_seed_keypair' to generate key pair which is
used for encryption process.
As I see some maths is involved here which I lack at present or I am failing to see the conversion.
I have to go this route Scrypt output -> key pair -> use for encryption
Using directly KeyGenerator from BC is working, but that utilises SecureRandom, but I need the output of Scrypt to behave as private key.
Questions:
I'll really appreciate someone helps me understand the difference between libSodium and Bouncy Castle approach. libSodium mentions it uses X25519. When I try to create X25519 key from 32 bytes, but BC Cipher(ECIESwithAES-CBC) then complaints it is not a EC Point, from this resource 'https://github.com/bcgit/bc-java/issues/251' it seems there are differences in that too (Curve25519 vs X25519).
The private key 'd', how to interpret it. I have seen these random values in Bouncy Castle documentation and test cases, is this simply a number in the prescribed range for valid keys? This number is treated (little vs. big endian) before creating BigInteger instance. I mean the raw value of 'd' in the my code example was converted from some other number?
The struggle between understanding different mechanism of Curve25519 and BC API itself, I am really confused.
Some pointers to further my research would be of great help.

Port Java AES ECB encryption into UWP compatible C# Code

I am very new in the field of cryptography and have been stuck on this problem for two days.
I have a java code for AES/ECB encryption and I want my uwp app to use the same encryption technique but whatever I've tried so far gives different encryption results.
There are many answers on stackoverflow suggesting to use RijndaelManaged class, but this class is not available for UWP.
Here's java snippet
public string encrypt(String input, string key) {
SecretKeySpec skey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skey);
crypted = cipher.doFinal(input.getBytes("UTF-8"));
return Base64.encodeToString(crypted,Base64.NO_WRAP);
}
You need to use this answer to see how to encrypt/decrypt. However, you need a different (ECB so insecure) algorithm. So instead of the given CBC cipher mode you need to use AesEcbPkcs7 from the SymmetricAlgorithmNames.
Notes:
PKCS#7 is the same as PKCS#5 as used in the Java code, more info here;
you of course don't need to use an IV for ECB mode, so strip that out;
the UTF-8 encoding and base 64 decoding I'll leave out, it should be easy to do these encodings in any language/environment (the Convert and UTF8Encoding classes seem to be available for UWP apps).

PHP crypt(pass, salt) alternative in Java - Blowfish algorithm

I'm using on php server function crypt like this:
$hash = crypt($password, '$2y$10$' . $salt);
It makes hash of password by Blowfish method.
I'm looking for java equivalent for crypt password.
I found this code, but I don't know where add $salt. More above:
String key = "abcd";
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(cipher.ENCRYPT_MODE, keySpec);
return DatatypeConverter.printBase64Binary(cipher.doFinal(key.getBytes()));
Thank's for every idea or answer.
Not an answer to your question but maybe it helps:
There is the Apache Commons Codec library that contains a Linux crypt(3) compatible function for at least des,md5,sha256 and sha512 based crypt() algorithms in case you don't really need blowfish but just something stronger than the traditional DES based hashes (use sha512 then):
http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Md5Crypt.java?view=markup
And there's other source code that implements the Blowfish algorithm but it's in C:
http://doxygen.postgresql.org/crypt-blowfish_8c_source.html
As you can see crypt() uses algorithms that are only based on those encryption ciphers but pipes the input several thousant times through them to get a nice hash value.
Now I did found some java implementations of crypt(3) with blowfish:
http://www.mindrot.org/projects/jBCrypt/ (last update 2010)
and
http://docs.spring.io/spring-security/site/docs/3.2.3.RELEASE/apidocs/org/springframework/security/crypto/bcrypt/BCrypt.html

Explanation to understand AES encryption code

I am creating a project to encrypt and decrypt a file. I have these two algorithms that work fine:
public static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
public static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
public static byte[] getRaw(String password_) throws Exception {
byte[] keyStart = password_.getBytes();
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
sr.setSeed(keyStart);
kgen.init(128, sr);
SecretKey skey = kgen.generateKey();
byte[] key = skey.getEncoded();
return key;
}
Now I need to explain how it works. Does it use a private key? Where is the key storage? Can anyone help me?
Note: see owlstead's answer for an excellent description of the flaws in your code example
Your encrypt() and decrypt() operations are performing AES encryption and decryption respectively, using Java's JCE libraries. A JCE provider will be selected to perform the actual cryptography - the provider chosen will be the first in the list of providers that offers an implementation of AES. You have defined the algorithm as only "AES", so the mode of operation and padding will be chosen by the provider. If you want to control this, use the form "AES/mode/padding" (see the docs for valid choices)
The getRaw method derives an AES key from a password. The raw bytes of the password provide the seed for a random number generator. The random number generator is then used to generate sufficient key material for a 128-bit AES key. A different password will produce a different seed, which should produce a different stream of random bytes and thus a different key. I suspect this approach is weakened by the lack of entropy present in most people's passwords, leading to a reduced key space and easier attacks.
There is no key storage in your example code. JCE keys are normally persisted using a KeyStore object and the storage mechanism is provider-dependent.
The above piece of code is a bunch of crap. Unfortunately it is frequently used as a code snippet for Android related code (Android code uses the same API as Java, so there is no need for an Android specific example, andt unfortunately it specifically fails on Android).
I'll explain the issues:
Using a SecureRandom as Password Based Key Derivation Function (PBKDF) is completely idiotic. The underlying implementation of the SecureRandom implementation may change. Furthermore, it is not specified by the SecureRandom that calling setSeed() as the first method will replace the seed; it may actually add the seed to the current state - and this is what certain newer android versions do.
Cipher.getInstance("AES") actually uses the provider defaults instead of specifying the mode of operation and padding mode for the given cipher. By default the Sun provider will use ECB mode which is not suitable for encrypting most data.
String.getBytes() - which is used for the password - returns the platform default encoding. Different platforms may have different default encodings. This means that different platforms will generate different keys.
Above code does not add a message authentication code (MAC or HMAC). This may lead to an attacker changing random ciphertext blocks, which leads to random plain text blocks. This may lead to loss of confidentiality as well if padding Oracle attacks apply.
It seems to me that you are a beginner in cryptography. Please use a higher level standard such as RNCryptor compatible code, or use a standard such as Cryptographic Message Syntax (CMS).

Problems encoding/decoding using AES-128-CBC

So basically I have these snippets of code and would like them to produce the same output:
require 'openssl'
aes = OpenSSL::Cipher::Cipher.new("AES-128-CBC")
aes.key = "aaaaaaaaaaaaaaaa"
aes.iv = "aaaaaaaaaaaaaaaa"
aes.encrypt
encrypted = aes.update("1234567890123456") << aes.final
puts encrypted.unpack('H*').join
This prints:
8d3bbffade308f8e4e80cb77ecb8df19ee933f75438cec1315c4a491bd1b83f4
And this Java code:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
String key = "aaaaaaaaaaaaaaaa";
String textToEncryptpt = "1234567890123456";
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(key.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(textToEncryptpt.getBytes());
System.out.println(Crypto.bytesToHex(encrypted));
Prints:
2d3760f53b8b3dee722aed83224f418f9dd70e089ecfe9dc689147cfe0927ddb
Annoying thing is that it was working a couple of days ago... so I am not sure what happened. What's wrong with this code? Do you see anything unusual?
Ruby script is wrong. You have to first call the encrypt method, and then set the key and iv:
require 'openssl'
aes = OpenSSL::Cipher::Cipher.new("AES-128-CBC")
aes.encrypt
aes.key = "aaaaaaaaaaaaaaaa"
aes.iv = "aaaaaaaaaaaaaaaa"
encrypted = aes.update("1234567890123456") << aes.final
puts encrypted.unpack('H*').join
I figured out because when trying to decode an encrypted string I got:
aescrypt.rb:13:in `final': bad decrypt (OpenSSL::Cipher::CipherError)
from aescrypt.rb:13:in `<main>'
Seems you found already the reason that your script does give different results.
Some more things to consider:
Don't ever hardcode the key in the program - that way you can't easily change it, and if someone gets access to your program code, she also gets to see the key.
Don't ever use a constant initialization vector. Instead, generate a random one and send it together with the ciphertext. Alternatively, if you generate the key from a password and some salt, you can also generate the IV from the same ... but don't use the key directly as IV.
Your key/IV values are strings, not bytes. String.getBytes() (in Java) converts the string to bytes using some encoding. The encoding used is system-dependent, and none of the usual String encodings (UTF-8, Latin-1, ...) can represent all bytes as printable (and typeable) characters. Preferably use something like Base64 or hex-encoding, if you have to store your key as string.
And whenever you transform a string to bytes, specify an encoding (and use the same encoding later for retrieving it).
#Cristian, For key and initial vector, you can create a function by using today's date plus the secure fixed keyword.
Eg: key = January 8, 2012 + Key
And for initial vector,
Eg: iv = January 8, 2012 + IV
Then enter that data(key and iv) to MD5 it will produce the output 16 bytes that you can use for the Key and IV. Every day, key and iv will change randomly.
Make sure both systems use the same date format and setup on the same date.

Categories

Resources