Using Oracle Phaos for client-side data encryption and server-side decryption.
Oracle Phaos Products provide the tools for enabling identity management security and standards-based cryptographic protocols. Components include support for encryption, certificate management, secure messaging, secure communications, XML encryption and digital signature, and secure federation. These products are Java-based with some components offering support for Java Runtime Environments as early as 1.1.7.
Image 1: Phaos data encryption over Oracle TNS.
In most cases if you don't use secure connection between client and server, some information will be captured in the communication channel.
To solve this issue Oracle recommend Advanced Security, but it´s only purchased in Enterprise Edition option.
Phaos RSAKeyPairGenerator class provide methods for generate RSA key pair. The module and the exponent of both keys (public and private) will be stored in database table (DATA_CRYPTO). Calling stored procedure you will obtain the exponent and modulus of the public key and encrypt data for client-side encryption and then send encrypted data to the server for server-side decryption. Also, you can save encrypted data in database and then you can decrypt it.
For example, some applications can use stored procedure in Oracle to create user in database. User's password will be send in plain text to the server. Implementing client-side data encryption we can avoid the risk of sniffer attacks or others techniques.
In the following session we explain how to use client-side data encryption and server-side data decryption using Oracle Phaos.
Loading Phaos library into Oracle Database:
Execute the following commands into the server console to load Phaos library into database.
Code Listen 1: loadjava is useful to load library into database and then resolve PHAOS class inside Oracle. Our database is DB1.
# cd $ORACLE_HOME/sysman/jlib
# $ORACLE_HOME/bin/loadjava phaos.jar -user sys@db1 -resolve -synonym
Create RSA Java Source:
Code Listen 2: Implementation of RSA java source.
create or replace and compile java source named rsa as
import java.math.BigInteger;
import com.phaos.crypto.*;
import java.sql.*;
import com.phaos.utils.*;
public class key_Pair {
private static RSAPublicKey pu_key;
private static RSAPrivateKey pv_key;
private static BigInteger PUK_modulus;
private static BigInteger PUK_exponent;
private static BigInteger PVK_modulus;
private static BigInteger PVK_exponent;
public static void set_Public_Key(RSAPublicKey _pu_key)
{
pu_key = _pu_key;
PUK_modulus = ((RSAPublicKey) pu_key).getModulus();
PUK_exponent = ((RSAPublicKey) pu_key).getExponent();
}
public static void set_Private_Key(RSAPrivateKey _pv_key)
{
pv_key = pv_key;
PVK_modulus = ((RSAPrivateKey) pv_key).getModulus();
PVK_exponent = ((RSAPrivateKey) pv_key).getExponent();
}
public static RSAPublicKey get_Public_Key()
{
return pu_key;
}
public static RSAPrivateKey get_Private_Key()
{
return pv_key;
}
public static byte[] privateToByte()
{
return pv_key.getEncoded();
}
public static byte[] publicToByte()
{
return pu_key.getEncoded();
}
public static BigInteger get_Public_Modulus()
{
return ((RSAPublicKey) pu_key).getModulus();
}
public static BigInteger get_Public_Exponent()
{
return ((RSAPublicKey) pu_key).getExponent();
}
public static BigInteger get_Private_Modulus()
{
return ((RSAPrivateKey) pv_key).getModulus();
}
public static BigInteger get_Private_Exponent()
{
return ((RSAPrivateKey) pv_key).getExponent();
}
}
public class Asymmetric_Cipher {
public static key_Pair GetKeys() throws Exception
{
RSAKeyPairGenerator rkp = new RSAKeyPairGenerator();
rkp.setAlgID(AlgID.rsaEncryption);
rkp.initialize(1024, RandomBitsSource.getDefault()); //provide a RSA key of 1024.
KeyPair kp = rkp.generateKeyPair();
RSAPrivateKey priv_Key = (RSAPrivateKey)kp.getPrivate();
RSAPublicKey pub_Key = (RSAPublicKey)kp.getPublic();
key_Pair kpo = new key_Pair();
kpo.set_Public_Key(pub_Key);
kpo.set_Private_Key(priv_Key);
return kpo;
}
public static RSAPrivateKey Create_Private_Key(byte[] in_modulus, byte[] in_exponent) throws Exception
{
BigInteger modulus = new BigInteger(1,in_modulus);
BigInteger exponent = new BigInteger(1,in_exponent);
RSAPrivateKey privateKey = new RSAPrivateKey(modulus,exponent);
return privateKey;
}
public static RSAPublicKey Create_Public_Key(byte[] in_modulus, byte[] in_exponent) throws Exception
{
BigInteger modulus = new BigInteger(in_modulus);
BigInteger exponent = new BigInteger(in_exponent);
RSAPublicKey publicKey = new RSAPublicKey(modulus,exponent);
return publicKey;
}
public static byte[] encrypt(byte[] inpBytes, RSAPublicKey key) throws Exception
{
Cipher rsaEnc = Cipher.getInstance(key);
rsaEnc.setAlgID(AlgID.rsaEncryption);
byte[] encryptedData = rsaEnc.encrypt(inpBytes);
return encryptedData;
}
public static byte[] decrypt(byte[] inpBytes, RSAPrivateKey key) throws Exception
{
Cipher rsaEnc = Cipher.getInstance(key);
rsaEnc.setAlgID(AlgID.rsaEncryption);
byte[] encryptedData = rsaEnc.decrypt(inpBytes);
return encryptedData;
}
}
public class Pair implements SQLData {
private String sql_type = "SCOTT.KEYS";
public static byte[] Public_Modulus;
public static byte[] Public_Exponent;
public static byte[] Private_Modulus;
public static byte[] Private_Exponent;
public Pair () {}
public String getSQLTypeName() throws SQLException { return sql_type; }
public void readSQL(SQLInput stream, String typeName) throws SQLException
{
sql_type = typeName;
Public_Modulus = stream.readBytes();
Public_Exponent = stream.readBytes();
Private_Modulus = stream.readBytes();
Private_Exponent = stream.readBytes();
}
public void writeSQL(SQLOutput stream) throws SQLException
{
stream.writeBytes(Public_Modulus);
stream.writeBytes(Public_Exponent);
stream.writeBytes(Private_Modulus);
stream.writeBytes(Private_Exponent);
}
}
public class Crypto_Core {
public static void Crypto_Core() throws Exception
{
}
public static String Decrypt_Message(byte[] message, byte[] modulus, byte[] exponent) throws Exception
{
String xform = "RSA";
RSAPrivateKey pk = Asymmetric_Cipher.Create_Private_Key(modulus, exponent);
byte[] decBytes = Asymmetric_Cipher.decrypt(message, pk);
return new String(decBytes,"UTF8");
}
public static byte[] Encrypt_Message(byte[] message, byte[] modulus, byte[] exponent) throws Exception
{
RSAPublicKey pbk = Asymmetric_Cipher.Create_Public_Key(modulus, exponent);
byte[] encBytes = Asymmetric_Cipher.encrypt(message, pbk);
return encBytes;
}
public static Pair GetKeys() throws Exception
{
key_Pair kp = new key_Pair();
kp = Asymmetric_Cipher.GetKeys();
Pair p = new Pair();
p.Public_Modulus = kp.get_Public_Modulus().toByteArray();
p.Public_Exponent = kp.get_Public_Exponent().toByteArray();
p.Private_Modulus = kp.get_Private_Modulus().toByteArray();
p.Private_Exponent = kp.get_Private_Exponent().toByteArray();
return p;
}
}
/
Create Table and Object:
Code Listen 3: Objects and tables required for implementation.
--Create Object Keys
CREATE OR REPLACE TYPE Keys AS OBJECT EXTERNAL NAME 'RSA.Pair' LANGUAGE JAVA
USING SQLData
(
PUBLIC_MODULUS RAW(1024) EXTERNAL NAME 'Public_Modulus',
PUBLIC_EXPONENT RAW(1024) EXTERNAL NAME 'Public_Exponent',
PRIVATE_MODULUS RAW(1024) EXTERNAL NAME 'Private_Modulus',
PRIVATE_EXPONENT RAW(1024) EXTERNAL NAME 'Private_Exponent'
);
-- Create table DATA_CRYPTO
CREATE TABLE DATA_CRYPTO
(
PUBLIC_MODULUS BLOB,
PUBLIC_EXPONENT BLOB,
PRIVATE_MODULUS BLOB,
PRIVATE_EXPONENT BLOB
)
tablespace SYSTEM
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
Create package and procedures:
Code Listen 4: Procedures for interact with RSA java source.
CREATE OR REPLACE PACKAGE BODY pkg_crypto IS
FUNCTION get_keys RETURN keys AS
LANGUAGE JAVA NAME 'Crypto_Core.GetKeys() return Pair';
FUNCTION decrypt(message IN RAW, modulus IN RAW, exponent IN RAW)
RETURN VARCHAR2 AS
LANGUAGE JAVA NAME 'Crypto_Core.Decrypt_Message(byte[], byte[], byte[]) return String';
FUNCTION encrypt(message IN RAW, modulus IN RAW, exponent IN RAW)
RETURN RAW AS
LANGUAGE JAVA NAME 'Crypto.Encrypt_Message(byte[], byte[], byte[]) return byte[]';
PROCEDURE ganerate_keys IS
keypair keys;
BEGIN
keypair := get_keys;
DELETE FROM DATA_CRYPTO;
INSERT INTO DATA_CRYPTO
(PUBLIC_MODULUS, PUBLIC_EXPONENT, PRIVATE_MODULUS, PRIVATE_EXPONENT)
VALUES
(keypair.PUBLIC_MODULUS,
keypair.PUBLIC_EXPONENT,
keypair.PRIVATE_MODULUS,
keypair.PRIVATE_EXPONENT);
END;
PROCEDURE get_key_data(v_modulus OUT RAW, v_exponent OUT RAW) IS
BEGIN
SELECT dc.PUBLIC_MODULUS, dc.PUBLIC_EXPONENT
INTO v_modulus, v_exponent
FROM DATA_CRYPTO dc;
v_modulus := dbms_lob.substr(v_modulus,128,2);
END;
PROCEDURE decrypt_message(in_menssage RAW, out_message OUT VARCHAR2) IS
prm_in_menssage RAW(1024) := in_menssage;
prm_out_message VARCHAR2(4000);
private_modulus RAW(129);
private_exponent RAW(128);
BEGIN
SELECT dc.PRIVATE_MODULUS, dc.PRIVATE_EXPONENT
INTO private_modulus, private_exponent
FROM DATA_CRYPTO dc;
private_modulus := dbms_lob.substr(private_modulus,128,2);
prm_out_message := decrypt(prm_in_menssage, private_modulus, private_exponent);
out_message := prm_out_message;
END;
PROCEDURE decrypt_message_java(in_menssage RAW, out_message OUT VARCHAR2) IS
prm_in_menssage RAW(1024) := in_menssage;
prm_out_message VARCHAR2(4000);
private_modulus RAW(129);
private_exponent RAW(128);
BEGIN
SELECT dc.PRIVATE_MODULUS, dc.PRIVATE_EXPONENT
INTO private_modulus, private_exponent
FROM DATA_CRYPTO dc;
prm_out_message := decrypt(prm_in_menssage, private_modulus, private_exponent);
out_message := prm_out_message;
END;
PROCEDURE encrypt_message(in_message RAW, out_message OUT RAW) IS
prm_in_menssage RAW(1024) := in_message;
prm_out_message RAW(1024);
private_modulus RAW(129);
private_exponent RAW(3);
BEGIN
SELECT dc.PRIVATE_MODULUS, dc.PRIVATE_EXPONENT
INTO private_modulus, private_exponent
FROM DATA_CRYPTO dc;
prm_out_message := encrypt(prm_in_menssage, private_modulus, private_exponent);
out_message := prm_out_message;
END;
END pkg_crypto;
/
Generating Keys:
First, you have generate keys for data encryption or decryption. You can generate a 256, 512 or 1024 RSA key with only change the value in method GetKeys of Asymetric_Cipher class.
Code Listen 5: Generating public and private key, data will be saved in DATA_CRYPTO table.
Begin
pkg_crypto.ganerate_keys;
commit;
End;
Encrypting and decrypting messages inside the database:
Code Listen 6: This example encrypt an string and decrypt it then.
declare
message VARCHAR2(250) := 'This is the test message';
encrypted_bytes RAW;
decrypted_message VARCHAR2(250);
begin
-- Call the procedure
pkg_crypto.encrypt_message(in_message => message,
out_message => encrypted_bytes);
pkg_crypto.decrypt_message_java(in_message => encrypted_bytes,
out_message => decrypted_message); //for decrypt data encrypted with pkg_crypto.encrypt_message method
dbms_output.put_line(decrypted_message);
end;
If you want use C# .NET to encrypt data you can use pkg_crypto.decrypt_message method to decrypt it.
Code Listen 6: This method return a byte array that content the encrypted string using public modulus and exponent.
public static byte [] EncryptPKI(string str)
{
CRIPTOGRAFIAFactory fact = new CRIPTOGRAFIAFactory(); //Object CRIPTOGRAFIAFactory is a factory that //implements method to get modulus
//and exponent from database
byte[] modulus = null;
byte[] exponent = null;
fact.GetKeys(ref modulus, ref exponent); //The GetKey method get information from database.
RSACryptoServiceProvider prv = new RSACryptoServiceProvider();
RSAParameters prm = new RSAParameters();
prm.Modulus = modulus;
prm.Exponent = exponent;
prv.ImportParameters( prm );
byte encrypt = prv.Encrypt(Encoding.UTF8.GetBytes(str), false );
return encrypt;
}
Then you can send this information to the database calling an stored procedure and inside the database decrypt the string.
Note: This implementation was tested with RSA 1024 key and raws less than 1024 bytes
Conclusions:
Oracle Phaos products provide more security to your applications. In this article we provides an interface to call Phaos RSA methods to encrypt and decrypt information, in RSA java source. Is important always protect the private key. You can use alternate mechanisms to save keys in Oracle Wallet or other structure.


