File Encryption with the Java Cryptography Architecture using AES with a 128-bit key and PBKDF2 - encryption

I am getting this error when I am decrypting a file
I am using PBKDF2 to convert a passphrase to a key and then using it. The encryption is working good but when I am trying to decrypt the same file it is giving the below error. The decrypted file gives a correct data except for the last few lines(probably the padding area). I have debugged it by outputting the IV and key while encrypting and decrypting and they both are the same but the error still exists.
public class FileEncryptorSkeleton{
private static final String progName = "FileEncryptor";
private static final int bufSize = 128;
/**
* #param args
*/
public static void main(String[] args) throws UnsupportedEncodingException {
BufferedInputStream in = null; // A buffered input stream to read from
BufferedOutputStream out = null; // And a buffered output stream to write to
SecretKeyFactory kf = null; // Something to create a key for us
KeySpec ks = null; // This is how we specify what kind of key we want it to generate
byte[] salt = new byte[20]; // Some salt for use with PBKDF2, only not very salty
SecretKey key = null; // The key that it generates
Cipher cipher = null; // The cipher that will do the real work
SecretKeySpec keyspec = null; // How we pass the key to the Cipher
int bytesRead = 0; // Number of bytes read into the input file buffer
byte[] iv = new byte[16];
// First, check the user has provided all the required arguments, and if they haven't, tell them then exit
if(args.length != 4) {
printUsageMessage(); System.exit(1);
}
// Open the input file
try {
in = new BufferedInputStream(new FileInputStream(args[1]));
} catch (FileNotFoundException e) {
printErrorMessage("Unable to open input file: " + args[1], null);
System.exit(1);
}
// And then the output file
try {
out = new BufferedOutputStream(new FileOutputStream(args[2]));
} catch (FileNotFoundException e) {
printErrorMessage("Unable to open output file: " + args[2], e);
System.exit(1);
}
try {
kf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
}
// Set up a KeySpec for password-based key generation of a 128-bit key
ks = new PBEKeySpec(args[3].toCharArray(), salt, 1000, 128);
// Now run the passphrase through PBKDF2 to get the key
try {
key = kf.generateSecret(ks);
}catch(InvalidKeySpecException e){
System.exit(1);
}
// Get the byte encoded key value as a byte array
byte[] aeskey = key.getEncoded();
// Now generate a Cipher object for AES encryption in ECBC mode with PKCS #5 padding
// Use ECB for the first task, then switch to CBC for versions 2 and 3
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException e) {
printErrorMessage("No Such Algorithm Exception when creating main cipher", e);
System.exit(2);
} catch (NoSuchPaddingException e) {
printErrorMessage("No Such Padding Exception when creating main cipher",e);
System.exit(2);
}
// Set a variable to indicate whether we're in encrypt or decrypt mode, based upon args[0]
int cipherMode = -1;
char mode = Character.toLowerCase(args[0].charAt(0));
switch (mode) {
case 'e' : cipherMode = Cipher.ENCRYPT_MODE; break;
case 'd' : cipherMode = Cipher.DECRYPT_MODE; break;
default: printUsageMessage(); System.exit(1);
}
// Set up a secret key specification, based on the 16-byte (128-bit) AES key array previously generated
keyspec = new SecretKeySpec(aeskey, "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv);
// Now initialize the cipher in the right mode, with the keyspec and the ivspec
try {
cipher.init(cipherMode, keyspec,ivspec);
} catch (InvalidKeyException e) {
printErrorMessage("Invalid Key Spec",e); System.exit(2);
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
}
// Set up some input and output byte array buffers
byte[] inputBuffer = new byte[bufSize];
byte[] outputBuffer = null;
// "Prime the pump" - we've got to read something before we can encrypt it
// and not encrypt anything if we read nothing.
try {
bytesRead = in.read(inputBuffer);
} catch (IOException e) {
printErrorMessage("Error reading input file " + args[1],e); System.exit(1);
}
// As long as we've read something, loop around encrypting, writing and reading
// bytesRead will be zero if nothing was read, or -1 on EOF - treat them both the same
while (bytesRead > 0) {
// Now encrypt this block
outputBuffer = cipher.update(inputBuffer.toString().getBytes("UTF-8"));
// Write the generated block to file
try {
out.write(outputBuffer);
} catch (IOException e) {
printErrorMessage("Error writing to output file " + args[2],e); System.exit(1);
}
// And read in the next block of the file
try {
bytesRead = in.read(inputBuffer);
} catch (IOException e) {
printErrorMessage("Error reading input file " + args[1],e); System.exit(1);
}
}
try {
// Now do the final processing
outputBuffer =cipher.doFinal(inputBuffer.toString().getBytes("UTF-8"));
cipher.init(cipherMode, keyspec,ivspec);
System.out.println(ivspec+" "+cipherMode+" "+keyspec);
} catch (IllegalBlockSizeException ex) {
Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
} catch (BadPaddingException ex) {
Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidKeyException ex) {
Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
}
// Write the final block of output
try {
out.write(outputBuffer);
} catch (IOException e) {
printErrorMessage("Error on final write to output file " + args[2],e); System.exit(1);
}
// Close the output files
try {
in.close();
out.close();
} catch (IOException e) {
printErrorMessage("Error closing file", e);
}
// If we were continuing beyond this point, we should really overwrite key material, drop KeySpecs, etc.
}
/**
* Print an error message on , optionally picking up additional detail from
* a passed exception
* #param errMsg
* #param e
*/
private static void printErrorMessage(String errMsg, Exception e) {
System.err.println(errMsg);
if (e != null)
System.err.println(e.getMessage());
}
/**
* Print a usage message
*/
private static void printUsageMessage() {
System.out.println(progName + " $Revision: 1.1 $: Usage: " + progName + " E/D infile outfile passphrase");
}
}
Oct 18, 2019 11:27:46 PM FileEncryptorSkeleton main
SEVERE: null
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)
at com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2164)
at FileEncryptorSkeleton.main(FileEncryptorSkeleton.java:174)

Both the Cipher#update- and Cipher#doFinal-method use inputBuffer.toString(), which only contains the name of the object's class and the hashcode and not the actual data in the buffer.
It would be correct to read the first bytesRead bytes from the inputBuffer-byte[] (which were previously read from the in-BufferedInputStream) and process them (Cipher#update):
outputBuffer = cipher.update(inputBuffer, 0, bytesRead);
The loop containing the cipher#update-call is only left when no byte has been read to the inputBuffer-byte[], so that for the final processing applies (Cipher#doFinal):
outputBuffer = cipher.doFinal();
In addition, the second cipher#init-call immediately after the cipher#doFinal-call is unnecessary (Cipher#init).

Related

If there is data, how is the stream returning zero bytes?

I have a RXTX project that I'm working on. I have it set ups as follows:
public void doConnect(ActionEvent event)
{
String selectedPort = (String)connectTabController.portList.getValue();
System.out.println("Connecting to: " + selectedPort);
selectedPortIdentifier = (CommPortIdentifier)portMap.get(selectedPort);
CommPort commPort = null;
try
{
commPort = selectedPortIdentifier.open("AT QC ReponseTime", TIMEOUT);
serialPort = (SerialPort)commPort;
setConnected(true);
if (isConnected)
{
if (initIOStream() == true)
{
initListener();
System.out.println("Initializing listener");
connectTabController.gui_changeStatusLabel("Device Connected!");
}
}
}
catch (PortInUseException e)
{
System.out.println("Port In use! " + e.toString());
}
catch (Exception e)
{
System.out.println("Failed to open! " + e.toString());
}
}
public boolean initIOStream()
{
//return value for whether opening the streams is successful or not
boolean successful = false;
try {
//
input = serialPort.getInputStream();
output = serialPort.getOutputStream();
writeData(RESETTPOD);
System.out.println("Writing Reset command");
successful = true;
System.out.println("IO Stream opened successfully!");
return successful;
}
catch (IOException e) {
System.out.println("I/O Streams failed to open. (" + e.toString() + ")");
return successful;
}
}
public void initListener()
{
try
{
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
}
catch (TooManyListenersException e)
{
System.out.println("Too many listeners. (" + e.toString() + ")");
}
}
That's how the connection is made, and it has a listener that's supposed to notify when data is available, which triggers the following:
#Override
public void serialEvent(SerialPortEvent evt) {
BufferedReader reader = null;
if (evt.getEventType() == SerialPortEvent.DATA_AVAILABLE)
{
try
{
reader = new BufferedReader(new InputStreamReader(input));
if (reader.ready())
{
fullLine = reader.readLine();
System.out.println(fullLine + "\n");
}
}
catch (Exception e)
{
System.out.println("#SerialEvent Failed to read data. (" + e.toString() + ")");
}
}
}
However, I keep getting "UNDERLYING INPUT STREAM RETURNED ZERO BYTES"
This makes no sense, since if there is nothing to read then the listener shouldnt be triggered int he first place. I tried running the app and I keep getting this error message around every 1/3 second, which corresponds to the burst-output of the device that's sending data. (which works fine in programs like PuttY)
If you are going to use the BufferedReader, take a look at the refence API document for javax.comm, CommPort and getInputStream. Then try using different settings for threshold and receive timeout.
eg).
serialPort.enableReceiveThreshold(3);
serialPort.enableReceiveTimeout(1);
https://docs.oracle.com/cd/E17802_01/products/products/javacomm/reference/api/

How to Play decrypted file

For video's to be copy protected , I thought of
Step-1) encrypting video files with key.
step-2)Decrypting a file OR decrypt in memory stream.
Step-3) Play decrypted file OR Play from Memory stream.
I have succesfully encrypted and decrypted a video file with key. But don't know how to play decrypted file(.dnc file).
Can somebody will please help me to play video file from decrypted (File or Memory Stream).
Code for Decryption
private void Decryption(string filePath)
{
try
{
DateTime current = DateTime.Now;
string encName = filePath + "data" + ".enc";
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
#region Seperate key and data
byte[] alldata = File.ReadAllBytes(filePath);
byte[] getencryptedkey = new byte[128];
byte[] data = new byte[alldata.Length - 128];
for (int i = 0; i < alldata.Length - 128; i++)
{ data[i] = alldata[i]; }
for (int i = alldata.Length - 128, j = 0; i < alldata.Length; i++, j++)
{ getencryptedkey[j] = alldata[i]; }
using (BinaryWriter bw = new BinaryWriter(File.Create(encName)))
{
bw.Write(data);
bw.Close();
}
#endregion
#region key decryption
StreamReader reader = new StreamReader("PublicPrivateKey.xml");
string publicprivatekeyxml = reader.ReadToEnd();
RSA.FromXmlString(publicprivatekeyxml);
reader.Close();
byte[] decryptedKey = RSA.Decrypt(getencryptedkey, false);
pwd = System.Text.ASCIIEncoding.Unicode.GetString(decryptedKey);
byte[] dk = null;
byte[] div = null;
crm.getKeysFromPassword(pwd, out dk, out div);
cryptoKey = dk;
cryptoIV = div;
#endregion
string ext = Path.GetExtension(encName).ToLower();
if (ext != ".enc")
{
MessageBox.Show("Please Enter correct File");
return;
}
string dncName = Path.GetDirectoryName(encName) + "\\" + Path.GetFileNameWithoutExtension(encName);
dncName = current.Date.Day.ToString() + current.Date.Month.ToString() + current.Date.Year.ToString() + current.TimeOfDay.Duration().Hours.ToString() + current.TimeOfDay.Duration().Minutes.ToString() + current.TimeOfDay.Duration().Seconds.ToString() + ".wmv";
try
{
if (crm.DecryptData(encName, dncName, cryptoKey, cryptoIV))
{
FileInfo fi = new FileInfo(encName);
FileInfo fi2 = new FileInfo(dncName);
if ((fi.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
{ fi.Attributes &= ~FileAttributes.ReadOnly; }
//copy creation and modification time
fi2.CreationTime = fi.CreationTime;
fi2.LastWriteTime = fi.LastWriteTime;
//delete encrypted file
File.Delete(encName);
MessageBox.Show("File Decrypted");
}
else
{
MessageBox.Show("The file can't be decrypted - probably wrong password");
}
}
catch (CryptographicException ex)
{ MessageBox.Show(ex.Message); }
catch (IOException ex)
{ MessageBox.Show(ex.Message); }
catch (UnauthorizedAccessException ex)
{ //i.e. readonly
MessageBox.Show(ex.Message);
}
}
catch (Exception ex)
{ MessageBox.Show(ex.Message); }
}
To copy-protect a video file, the best way to accomplish it used to be apply DRM to it. That way you can restrict how may times it should play or how long it should be available to the user, but that still could be broken via a lot of means.
You cannot make any video 100% copy protected. Please read the article below. If that was the case, the hollywood movies wouldnt be freely available via the torrent networks.
http://www.streamingmedia.com/Articles/Editorial/Featured-Articles/DRM-Is-Dead-79353.aspx

Datatype mismatch for blob type blackberry

I have an exception that Datatype mismatch in this line
byte[] _data = (byte[])row.getBlobBytes(1);
and in the table I have the type of column 2 is BLOB.
public static UrlRsc getContentUrl(String name) {
UrlRsc elementRsc = null;
try {
Statement statement = DB
.createStatement("SELECT * FROM table where"
+ " Name='"
+ name + "'");
statement.prepare();
Cursor cursor = statement.getCursor();
Row row;
while (cursor.next()) {
row = cursor.getRow();
byte[]_data;
_data = row.getBlobBytes(1);
}
statement.close();
cursor.close();
} catch (DatabaseException dbe) {
System.out.println(dbe.toString());
} catch (DataTypeException dte) {
System.out.println(dte.toString());
}
return elementRsc;
}
Can any one help me ?
Hi i am using following code for save image in my local database and i got success. i just posted my 3 methods
Note: When i am inserting image into data base i changed that image in byte array then only i can save into that table
1)Table creation 2) table insertion 3)image retrieving from table
ContactImage_table creation
public ContactImageTableCreation(){
try{
Statement stmt=DATABASE.createStatement("create table if not exists 'ContactImage_table'(ID 'TEXT',image 'blob',NodeId 'TEXT')");
stmt.prepare();
stmt.execute();
stmt.close();
}catch(Exception e){
System.out.println(e.getMessage());
}
}
Insert data into ContactImage_table
public void ContactImageTableInsertion(){
try{
Statement st=DATABASE.createStatement("insert into ContactImage_table (ID,Image,NodeId)values(?,?,?)");
st.prepare();
st.bind(1, "101");
st.bind(2, BYTE_ARRY);
st.bind(3,"103");
st.execute();
st.close();
}catch (Exception e) {
System.out.println(e.getMessage());
}
}
Retrieving data from ContactImage_table
public ContactImageTableDataRetriving(){
try{
Statement st=DATABASE.createStatement("select * from ContactImage_table");
st.prepare();
Cursor c=st.getCursor();
Row r;
int i=0;
while(c.next()){
r=c.getRow();
i++;
// ContactImageObject is a wrapper class for data handling
contactImageObj=new ContactImageObject();
contactImageObj.setId(r.getString(0));
byte[] decoded=r.getBlobBytes(1);
EncodedImage fullImage = EncodedImage.createEncodedImage(decoded, 0, decoded.length);
Bitmap b=fullImage.getBitmap();
contactImageObj.setImage(b);
// System.out.println("Successfully retrived");
if(i==0){
// System.out.println("No Records");
}
}
st.close();
}catch (Exception e) {
// System.out.println(e.getMessage());
}
}
just cross check your code with this code snippet hope you will get resolve all the best

SAML2 assertion encryption using public key (opensaml)

I've recently tried to encrypt Saml2 assertion using relaying-party service public key. Unfortunately I can't finalise even the test phase
here is my code
public class EncryptionTest {
public static void main(String args[]){
try {
// The Assertion to be encrypted
FileInputStream fis;
DataInputStream in, in2;
File f = new File("src/main/resources/AssertionTest");
byte[] buffer = new byte[(int) f.length()];
in = new DataInputStream(new FileInputStream(f));
in.readFully(buffer);
in.close();
//Assertion = DataInputStream.readUTF(in);
String in_assert = new String(buffer);
System.out.println(in_assert);
org.apache.axiom.om.OMElement OMElementAssertion = org.apache.axiom.om.util.AXIOMUtil.stringToOM(in_assert);
Assertion assertion = convertOMElementToAssertion2(OMElementAssertion);
// Assume this contains a recipient's RSA public key
Credential keyEncryptionCredential;
keyEncryptionCredential = getCredentialFromFilePath("src/main/resources/cert.pem");
EncryptionParameters encParams = new EncryptionParameters();
encParams.setAlgorithm(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128);
KeyEncryptionParameters kekParams = new KeyEncryptionParameters();
kekParams.setEncryptionCredential(keyEncryptionCredential);
kekParams.setAlgorithm(EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP);
KeyInfoGeneratorFactory kigf =
Configuration.getGlobalSecurityConfiguration()
.getKeyInfoGeneratorManager().getDefaultManager()
.getFactory(keyEncryptionCredential);
kekParams.setKeyInfoGenerator(kigf.newInstance());
Encrypter samlEncrypter = new Encrypter(encParams, kekParams);
samlEncrypter.setKeyPlacement(KeyPlacement.PEER);
EncryptedAssertion encryptedAssertion = samlEncrypter.encrypt(assertion);
System.out.println(encryptedAssertion);
} catch (EncryptionException e) {
e.printStackTrace();
} catch (CertificateException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (KeyException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (XMLStreamException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
}
public static Credential getCredentialFromFilePath(String certPath) throws IOException, CertificateException, KeyException {
InputStream inStream = new FileInputStream(certPath);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(inStream);
inStream.close();
//"Show yourself!"
System.out.println(cert.toString());
BasicX509Credential cred = new BasicX509Credential();
cred.setEntityCertificate((java.security.cert.X509Certificate) cert);
cred.setPrivateKey(null);
//System.out.println(cred.toString());
return cred;
//return (Credential) org.opensaml.xml.security.SecurityHelper.getSimpleCredential( (X509Certificate) cert, privatekey);
}
public static Assertion convertOMElementToAssertion2(OMElement element) {
Element assertionSAMLDOOM = (Element) new StAXOMBuilder(DOOMAbstractFactory.getOMFactory(), element.getXMLStreamReader()).getDocumentElement();
try {
UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(Assertion.DEFAULT_ELEMENT_NAME);
return (Assertion) unmarshaller.unmarshall(assertionSAMLDOOM);
} catch (Exception e1) {
System.out.println("error: " + e1.toString());
}
return null;
}
}
I constantly recive Null pointer exception in
KeyInfoGeneratorFactory kigf =
Configuration.getGlobalSecurityConfiguration()
.getKeyInfoGeneratorManager().getDefaultManager()
.getFactory(keyEncryptionCredential);
kekParams.setKeyInfoGenerator(kigf.newInstance());
How can I set GlobalSecurityConfiguration or is there different approach of encrypting Assertion which will work?
This question was laying open for too long. The problem was initialization of OpenSaml.
Simple
DefaultBootstrap.bootstrap();
helped and solved problem.

How do encrypt a long or int using the Bouncy Castle crypto routines for BlackBerry?

How do encrypt/decrypt a long or int using the Bouncy Castle crypto routines for BlackBerry? I know how to encrypt/decrypt a String. I can encrypt a long but can't get a long to decrypt properly.
Some of this is poorly done, but I'm just trying stuff out at the moment.
I've included my entire crypto engine here:
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
public class CryptoEngine
{
// Global Variables
// Global Objects
private static AESFastEngine engine;
private static BufferedBlockCipher cipher;
private static KeyParameter key;
public static boolean setEncryptionKey(String keyText)
{
// adding in spaces to force a proper key
keyText += " ";
// cutting off at 128 bits (16 characters)
keyText = keyText.substring(0, 16);
keyText = HelperMethods.cleanUpNullString(keyText);
byte[] keyBytes = keyText.getBytes();
key = new KeyParameter(keyBytes);
engine = new AESFastEngine();
cipher = new PaddedBufferedBlockCipher(engine);
// just for now
return true;
}
public static String encryptString(String plainText)
{
try
{
byte[] plainArray = plainText.getBytes();
cipher.init(true, key);
byte[] cipherBytes = new byte[cipher.getOutputSize(plainArray.length)];
int cipherLength = cipher.processBytes(plainArray, 0, plainArray.length, cipherBytes, 0);
cipher.doFinal(cipherBytes, cipherLength);
String cipherString = new String(cipherBytes);
return cipherString;
}
catch (DataLengthException e)
{
Logger.logToConsole(e);
}
catch (IllegalArgumentException e)
{
Logger.logToConsole(e);
}
catch (IllegalStateException e)
{
Logger.logToConsole(e);
}
catch (InvalidCipherTextException e)
{
Logger.logToConsole(e);
}
catch (Exception ex)
{
Logger.logToConsole(ex);
}
// else
return "";// default bad value
}
public static String decryptString(String encryptedText)
{
try
{
byte[] cipherBytes = encryptedText.getBytes();
cipher.init(false, key);
byte[] decryptedBytes = new byte[cipher.getOutputSize(cipherBytes.length)];
int decryptedLength = cipher.processBytes(cipherBytes, 0, cipherBytes.length, decryptedBytes, 0);
cipher.doFinal(decryptedBytes, decryptedLength);
String decryptedString = new String(decryptedBytes);
// crop accordingly
int index = decryptedString.indexOf("\u0000");
if (index >= 0)
{
decryptedString = decryptedString.substring(0, index);
}
return decryptedString;
}
catch (DataLengthException e)
{
Logger.logToConsole(e);
}
catch (IllegalArgumentException e)
{
Logger.logToConsole(e);
}
catch (IllegalStateException e)
{
Logger.logToConsole(e);
}
catch (InvalidCipherTextException e)
{
Logger.logToConsole(e);
}
catch (Exception ex)
{
Logger.logToConsole(ex);
}
// else
return "";// default bad value
}
private static byte[] convertLongToByteArray(long longToConvert)
{
return new byte[] { (byte) (longToConvert >>> 56), (byte) (longToConvert >>> 48), (byte) (longToConvert >>> 40), (byte) (longToConvert >>> 32), (byte) (longToConvert >>> 24), (byte) (longToConvert >>> 16), (byte) (longToConvert >>> 8), (byte) (longToConvert) };
}
private static long convertByteArrayToLong(byte[] byteArrayToConvert)
{
long returnable = 0;
for (int counter = 0; counter < byteArrayToConvert.length; counter++)
{
returnable += ((byteArrayToConvert[byteArrayToConvert.length - counter - 1] & 0xFF) << counter * 8);
}
if (returnable < 0)
{
returnable++;
}
return returnable;
}
public static long encryptLong(long plainLong)
{
try
{
String plainString = String.valueOf(plainLong);
String cipherString = encryptString(plainString);
byte[] cipherBytes = cipherString.getBytes();
long returnable = convertByteArrayToLong(cipherBytes);
return returnable;
}
catch (Exception e)
{
Logger.logToConsole(e);
}
// else
return Integer.MIN_VALUE;// default bad value
}
public static long decryptLong(long encryptedLong)
{
byte[] cipherBytes = convertLongToByteArray(encryptedLong);
cipher.init(false, key);
byte[] decryptedBytes = new byte[cipher.getOutputSize(cipherBytes.length)];
int decryptedLength = cipherBytes.length;
try
{
cipher.doFinal(decryptedBytes, decryptedLength);
}
catch (DataLengthException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalStateException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InvalidCipherTextException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
long plainLong = convertByteArrayToLong(decryptedBytes);
return plainLong;
}
public static boolean encryptBoolean(int plainBoolean)
{
return false;
}
public static boolean decryptBoolean(int encryptedBoolean)
{
return false;
}
public static boolean testLongToByteArrayConversion()
{
boolean returnable = true;
// fails out of the bounds of an integer, the conversion to long from byte
// array does not hold, need to figure out a better solution
for (long counter = -1000000; counter < 1000000; counter++)
{
long test = counter;
byte[] bytes = convertLongToByteArray(test);
long result = convertByteArrayToLong(bytes);
if (result != test)
{
returnable = false;
Logger.logToConsole("long conversion failed");
Logger.logToConsole("test = " + test + "\n result = " + result);
}
// regardless
}
// the end
Logger.logToConsole("final returnable result = " + returnable);
return returnable;
}
}
It's probably the conversion from long -> byte[] -> String, in particular the conversion from String back into byte[]. You don't pass in an encoding for String.getBytes() so it's going to be using the default character encoding, which may be altering your data.
My suggestion is to expose encrypt/decrypt methods that take byte[] as an argument, to avoid String/byte[] conversion.
Also, you may want to take a look at the native RIM AES classes, AESEncryptorEngine and AESDecryptorEngine which may be faster than BouncyCastle (since they're native APIs) and require less code.
I just realized that with strong ciphers, the result length is usually/always greater than the length of the original. If it wasn't, a lookup table could be used. As such, its not possible to encrypt a long into a long every time, especially if it uses all 64 bits. If this doesn't make sense, see me for more info:
How do I encrypt a string and get a equal length encrypted string?

Resources