package org.openintents.safe;\r
\r
import java.io.ByteArrayInputStream;\r
+import java.io.File;\r
+import java.io.FileNotFoundException;\r
+import java.io.FileOutputStream;\r
import java.io.IOException;\r
+import java.io.InputStream;\r
import java.security.DigestInputStream;\r
import java.security.InvalidAlgorithmParameterException;\r
import java.security.InvalidKeyException;\r
import javax.crypto.spec.PBEKeySpec;\r
import javax.crypto.spec.PBEParameterSpec;\r
\r
+import android.content.ContentResolver;\r
+import android.net.Uri;\r
+import android.os.Environment;\r
import android.util.Log;\r
+import estreamj.ciphers.trivium.Trivium;\r
+import estreamj.framework.ESJException;\r
\r
/**\r
* Crypto helper class.\r
\r
return new String(plaintext);\r
}\r
+ \r
+\r
+ /**\r
+ * encrypt a string using a random session key\r
+ * \r
+ * @author Peli\r
+ * \r
+ * @param plaintext\r
+ * @return encrypted String\r
+ * @throws Exception\r
+ */\r
+ public Uri encryptFileWithSessionKey(ContentResolver contentResolver, Uri fileUri) throws CryptoHelperException {\r
+ Log.i(TAG, "Encrypt with session key");\r
+ status=false; // assume failure\r
+ if(password == null) {\r
+ String msg = "Must call setPassword before runing encrypt.";\r
+ throw new CryptoHelperException(msg);\r
+ }\r
+ \r
+ String outputPath = "";\r
+ try {\r
+ InputStream is;\r
+ if (fileUri.getScheme().equals("file")) {\r
+ is = new java.io.FileInputStream(fileUri.getPath());\r
+ outputPath = fileUri.getPath() + ".oisafe";\r
+ } else {\r
+ is = contentResolver.openInputStream(fileUri);\r
+ outputPath = Environment\r
+ .getExternalStorageDirectory().toString() + "/test.abc";\r
+ }\r
+ \r
+ FileOutputStream os = new FileOutputStream(outputPath);\r
+ \r
+ \r
+ byte[] cipherSessionKey = {};\r
+ byte[] ciphertext = {};\r
+ \r
+ // First create a session key\r
+ SecretKey sessionKey = null;\r
+ byte[] sessionKeyEncoded = null;\r
+ String sessionKeyString = null;\r
+ try {\r
+ KeyGenerator keygen;\r
+ keygen = KeyGenerator.getInstance("AES");\r
+ keygen.init(256); // needs 96 bytes\r
+ //keygen.init(128); // needs 64 bytes\r
+ sessionKey = keygen.generateKey();\r
+ sessionKeyEncoded = sessionKey.getEncoded();\r
+ sessionKeyString = new String(sessionKeyEncoded);\r
+ } catch (NoSuchAlgorithmException e) {\r
+ Log.e(TAG,"generateMasterKey(): "+e.toString());\r
+ }\r
+ \r
+ // Encrypt the session key using the master key\r
+ try {\r
+ pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);\r
+ cipherSessionKey = pbeCipher.doFinal(sessionKeyEncoded);\r
+ } catch (IllegalBlockSizeException e) {\r
+ Log.e(TAG,"encryptWithSessionKey(): "+e.toString());\r
+ } catch (BadPaddingException e) {\r
+ Log.e(TAG,"encryptWithSessionKey(): "+e.toString());\r
+ } catch (InvalidKeyException e) {\r
+ Log.e(TAG,"encryptWithSessionKey(): "+e.toString());\r
+ } catch (InvalidAlgorithmParameterException e) {\r
+ Log.e(TAG,"encryptWithSessionKey(): "+e.toString());\r
+ }\r
+ \r
+ String stringCipherVersion = "A";\r
+ byte[] bytesCipherVersion = stringCipherVersion.getBytes();\r
+ os.write(bytesCipherVersion, 0, bytesCipherVersion.length);\r
+ \r
+ os.write(cipherSessionKey, 0, cipherSessionKey.length);\r
+ \r
+ Log.d(TAG, "bytesCipherVersion.length: " + bytesCipherVersion.length);\r
+ Log.d(TAG, "cipherSessionKey.length: " + cipherSessionKey.length);\r
+ \r
+ Trivium tri = new Trivium();\r
+ try {\r
+ tri.setupKey(Trivium.MODE_ENCRYPT,\r
+ sessionKeyEncoded, 0);\r
+ tri.setupNonce(sessionKeyEncoded, 10);\r
+ \r
+ // Create the byte array to hold the data\r
+ final int bytesLen = 4096; // buffer length\r
+ byte[] bytesIn = new byte[bytesLen];\r
+ byte[] bytesOut = new byte[bytesLen];\r
+ \r
+ int offset = 0;\r
+ int numRead = 0;\r
+ while ((numRead = is.read(bytesIn, 0, bytesLen)) >= 0) {\r
+ if ((numRead | 3) != 0) {\r
+ Log.d(TAG, "Bytes read is inappropriate number: " + numRead);\r
+ }\r
+ \r
+ tri.process(bytesIn, 0,\r
+ bytesOut, 0, numRead);\r
+ \r
+ os.write(bytesOut, 0, numRead);\r
+ offset += numRead;\r
+ }\r
+ \r
+ // Ensure all the bytes have been read in\r
+ if (offset < is.available()) {\r
+ throw new IOException("Could not completely read file ");\r
+ }\r
+ \r
+ // Close the input stream and return bytes\r
+ is.close();\r
+ os.close();\r
+ \r
+ } catch (ESJException e) {\r
+ Log.e(TAG, "Error encrypting file", e);\r
+ }\r
+ } catch (FileNotFoundException e) {\r
+ Log.e(TAG, "File not found", e);\r
+ } catch (IOException e) {\r
+ Log.e(TAG, "IO Exception", e);\r
+ }\r
+ \r
+ return Uri.parse("file://" + outputPath);\r
+ }\r
+\r
+ /**\r
+ * unencrypt encrypted string previously encrypted with\r
+ * encryptWithSessionKey()\r
+ * \r
+ * @author Peli\r
+ * \r
+ * @param ciphertext\r
+ * @return decrypted String\r
+ * @throws Exception\r
+ */\r
+ public Uri decryptFileWithSessionKey(Uri fileUri) throws CryptoHelperException {\r
+ /*\r
+ status=false; // assume failure\r
+ if(password == null) {\r
+ String msg = "Must call setPassword before running decrypt.";\r
+ throw new CryptoHelperException(msg);\r
+ }\r
+ \r
+ if ((ciphertext==null) || (ciphertext=="")) {\r
+ return "";\r
+ }\r
+ String cipherVersion = null;\r
+ String cipherSessionKey = null;\r
+ \r
+ // Split cipher into session key and text\r
+ try {\r
+ cipherVersion = ciphertext.substring(0,1);\r
+ if (cipherVersion.equals("A")) {\r
+ cipherSessionKey = ciphertext.substring(1,97); // 64 if init(128) had been chosen\r
+ ciphertext = ciphertext.substring(97);\r
+ } else {\r
+ Log.e(TAG, "Unknown cipher version" + cipherVersion);\r
+ return "";\r
+ }\r
+ } catch (IndexOutOfBoundsException e) {\r
+ Log.e(TAG, "Invalid ciphertext (with session key)");\r
+ return "";\r
+ }\r
+ \r
+ // Decrypt the session key\r
+ byte[] byteCipherSessionKey=hexStringToBytes(cipherSessionKey);\r
+ byte[] byteSessionKey = {};\r
+ \r
+ try {\r
+ pbeCipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec);\r
+ byteSessionKey = pbeCipher.doFinal(byteCipherSessionKey);\r
+ status=true;\r
+ } catch (IllegalBlockSizeException e) {\r
+ Log.e(TAG,"decrypt(): "+e.toString());\r
+ } catch (BadPaddingException e) {\r
+ Log.e(TAG,"decrypt(): "+e.toString());\r
+ } catch (InvalidKeyException e) {\r
+ Log.e(TAG,"decrypt(): "+e.toString());\r
+ } catch (InvalidAlgorithmParameterException e) {\r
+ Log.e(TAG,"decrypt(): "+e.toString());\r
+ }\r
+\r
+ // Convert the session key into a Pbe key\r
+ String stringSessionKey = new String(byteSessionKey);\r
+ PBEKeySpec sessionPbeKeySpec = new PBEKeySpec(stringSessionKey.toCharArray());\r
+ SecretKey sessionPbeKey = null;\r
+ try {\r
+ sessionPbeKey = keyFac.generateSecret(sessionPbeKeySpec);\r
+ } catch (InvalidKeySpecException e) {\r
+ Log.e(TAG,"setPassword(): "+e.toString());\r
+ }\r
+\r
+ // Use the session key to decrypt the text\r
+ byte[] byteCiphertext=hexStringToBytes(ciphertext);\r
+ byte[] plaintext = {};\r
+ \r
+ try {\r
+ pbeCipher.init(Cipher.DECRYPT_MODE, sessionPbeKey, pbeParamSpec);\r
+ plaintext = pbeCipher.doFinal(byteCiphertext);\r
+ status=true;\r
+ } catch (IllegalBlockSizeException e) {\r
+ Log.e(TAG,"decrypt(): "+e.toString());\r
+ } catch (BadPaddingException e) {\r
+ Log.e(TAG,"decrypt(): "+e.toString());\r
+ } catch (InvalidKeyException e) {\r
+ Log.e(TAG,"decrypt(): "+e.toString());\r
+ } catch (InvalidAlgorithmParameterException e) {\r
+ Log.e(TAG,"decrypt(): "+e.toString());\r
+ }\r
+ \r
+ return new String(plaintext);\r
+ */\r
+ return null;\r
+ }\r
}\r