]> hydra-www.ietfng.org Git - android-vcpass-oisafe/commitdiff
OI Safe: Enhance encrypt intent to accept file URI in intent data.
authorpeli0101 <peli0101@72b678ce-9140-0410-bee8-679b907dd61a>
Sun, 29 Mar 2009 22:42:58 +0000 (22:42 +0000)
committerpeli0101 <peli0101@72b678ce-9140-0410-bee8-679b907dd61a>
Sun, 29 Mar 2009 22:42:58 +0000 (22:42 +0000)
git-svn-id: http://openintents.googlecode.com/svn/trunk/Safe@2008 72b678ce-9140-0410-bee8-679b907dd61a

AndroidManifest.xml
readme.txt
src/org/openintents/intents/CryptoIntents.java
src/org/openintents/safe/CryptoHelper.java
src/org/openintents/safe/IntentHandler.java

index b1e0de2c145b71ad5c377ce5afd1a3e05d001020..b2a3293bdbf651f035d9db2f520336c2044975d5 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.openintents.safe" \r
-    android:versionName="1.1.0" android:versionCode="6">\r
+    android:versionName="1.1.1" android:versionCode="7">\r
     <!-- History:\r
     1.1.0 [6]: 2009-03-17\r
     1.0.0 [4]: 2009-02-02\r
@@ -10,7 +10,7 @@
        \r
         <!-- aTrackDog metadata -->\r
         <meta-data android:name="com.a0soft.gphone.aTrackDog.testVersion"\r
-           android:value="5" />\r
+           android:value="7" />\r
         \r
         <!-- OI About metadata -->\r
                <meta-data android:name="org.openintents.metadata.COMMENTS"\r
                 <action android:name="org.openintents.action.ENCRYPT" />
                 <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
+               <intent-filter android:label="@string/intent_encrypt">\r
+                <action android:name="org.openintents.action.ENCRYPT" />\r
+                <category android:name="android.intent.category.DEFAULT" />\r
+                       <data android:scheme="file" />\r
+            </intent-filter>\r
                <intent-filter android:label="@string/intent_decrypt">
                 <action android:name="org.openintents.action.DECRYPT" />
                 <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
+               <intent-filter android:label="@string/intent_decrypt">\r
+                <action android:name="org.openintents.action.DECRYPT" />\r
+                <category android:name="android.intent.category.DEFAULT" />\r
+                       <data android:scheme="file" />\r
+            </intent-filter>\r
                <intent-filter android:label="@string/intent_get_password">
                 <action android:name="org.openintents.action.GET_PASSWORD" />
                 <category android:name="android.intent.category.DEFAULT" />
index 8169862b71bdb9f3c7c77a2c88fae0d0abd07e18..bc3d4c8b50941321265131d3cd9685eb54514331 100644 (file)
@@ -25,7 +25,14 @@ To obtain the current release, visit
   http://www.openintents.org\r
 \r
 ---------------------------------------------------------\r
-release: 1.0.1\r
+release: 1.1.1\r
+date: 2009-??\r
+\r
+- Add support for file encryption.\r
+- Add Trivium stream cipher.\r
+\r
+---------------------------------------------------------\r
+release: 1.1.0\r
 date: 2009-03-17\r
 \r
 - New touch keypad to unlock screen.\r
index a5b0e6eb990c9af9afdbc4d242488484f5fbb2af..f2d02e877baa017e0a1e09cc2e6f0537d21a481f 100644 (file)
@@ -16,7 +16,7 @@
 package org.openintents.intents;\r
 \r
 /**\r
- * @version Jan 11, 2008, 11:50 UTC\r
+ * @version March 29, 2009, 22:26 UTC\r
  * \r
  * @author Isaac Potoczny-Jones\r
  * @author Peli\r
@@ -27,6 +27,10 @@ public class CryptoIntents {
        /**\r
         * Activity Action: Encrypt all strings given in the extra(s) EXTRA_TEXT or\r
         * EXTRA_TEXT_ARRAY.\r
+        * \r
+        * If a file URI is given, the file is encrypted.\r
+        * The new file URI is returned.\r
+        * \r
         * Returns all encrypted string in the same extra(s).\r
         * \r
         * <p>Constant Value: "org.openintents.action.ENCRYPT"</p>\r
@@ -36,6 +40,10 @@ public class CryptoIntents {
        /**\r
         * Activity Action: Decrypt all strings given in the extra TEXT or\r
         * EXTRA_TEXT_ARRAY.\r
+        * \r
+        * If a file URI is given, the file is decrypted.\r
+        * The new file URI is returned.\r
+        * \r
         * Returns all decrypted string in the same extra(s).\r
         * \r
         * <p>Constant Value: "org.openintents.action.DECRYPT"</p>\r
index e5fcb601f34e4044eb0edeb7cc0dc50d885b5133..dfca0fd352f3f911b7fe22433a59b81187e59d12 100644 (file)
 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
@@ -37,7 +41,12 @@ import javax.crypto.SecretKeyFactory;
 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
@@ -538,4 +547,215 @@ public class CryptoHelper {
                \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
index 529e2307caa9107e98c3b8a89d9e5e57f9d4b0ac..a3ad44da6dfb04a0bfdecfa6325710261dae2cd1 100644 (file)
@@ -30,6 +30,7 @@ import android.content.Context;
 import android.content.Intent;\r
 import android.content.ServiceConnection;\r
 import android.content.SharedPreferences;\r
+import android.net.Uri;\r
 import android.os.Bundle;\r
 import android.os.IBinder;\r
 import android.os.RemoteException;\r
@@ -270,6 +271,14 @@ public class IntentHandler extends Activity {
                                callbackIntent.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, out);\r
                        }\r
                        \r
+                       if (thisIntent.getData() != null) {\r
+                               // Encrypt file\r
+                               Uri fileUri = thisIntent.getData();\r
+                               \r
+                               Uri newFileUri = ch.encryptFileWithSessionKey(getContentResolver(), fileUri);\r
+                               \r
+                               callbackIntent.setData(newFileUri);\r
+                       }\r
                        // Support for binary fields could be added here (like images?)\r
                        \r
                        callbackResult = RESULT_OK;\r