Mar 30, 2013

siwapp :: File does not exists error


We tested siwapp application, which is an opensource invoicing application, but we had some problems, the error log was full of these:



[Sat Mar 30 17:32:55 2013] [error] [client xx.xx.xx.xx] File does not exist: /home/invoice/web/invoices

The site seemed to work fine otherwise.

It seemed that there was a problem with the app's .htaccess.

The main problem was here:
RewriteCond %{REQUEST_URI} \..+$
which matches all files with a dot in the filename, but the rule was ment to match files that start with a dot.

The fix for this is:
RewriteCond %{REQUEST_URI} /\..+$

After that fix, the app created errors because of a request for favicon.ico.
Well, the fix for that is simple enough
RewriteRule .+/favicon.ico$ favicon.ico [L]

So the whole .htaccess looks like this:
Options +FollowSymLinks +ExecCGI -MultiViews

AddDefaultCharset utf-8 

 
    Order deny,allow
    Deny  from all
 

 
    Order deny,allow
    Deny  from all
 


  RewriteEngine On

  # Rule to test if rewrite module is available during
  # the install process
  RewriteRule test_rewrite1\.txt test_rewrite2.txt
  
  RewriteRule .+/favicon.ico$ favicon.ico [L]

  # uncomment the following line, if you are having trouble
  # getting no_script_name to work
  #RewriteBase /

  # we skip all files with .something
  RewriteCond %{REQUEST_URI} /\..+$
  RewriteCond %{REQUEST_URI} !\.html$
  RewriteRule .* - [L]

  # we check if the .html version is here (caching)
  RewriteRule ^$ index.html [QSA]
  RewriteRule ^([^.]+)$ $1.html [QSA]

  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f

  # no, so we redirect to our front web controller
  RewriteRule (.*) index.php [L,QSA]

Mar 25, 2013

Java, PHP :: RSA Asymmetric Encryption

Information Security and Privacy was a pretty fun and interesting class I had in college, I learned quite a lot of interesting new stuff, but when it came down to it, in practice, I had some problems implementing encrypted communication between Android (Java) frontend and PHP backend because of a tiny little detail.
Algorithm of choice was RSA and the most important part is to use "RSA/ECB/PKCS1PADDING" algorithm when calling Cipher instance in Java, other stuff is pretty straightforward.

RSA works like this.
Imagine a scenario where Alice sends an encrypted message to Bob.
As you can see, Alice encrypts data with Bob's public key, and only Bob can decrypt it, because only he has his private key.

Here's the Java code (Warning, some Android elements ahead)
public class Encryption {
 private static Key  privKey;
 private static PublicKey pubKey;
 private static PublicKey servPub;
 
 private static String  tag  = "Encryption";
 private static String[]  alg  = {"RSA","RSA/ECB/PKCS1PADDING"};
 private static String  hash  = "SHA1";
 private static String  serverPubKeyB64 = ""; //Bob's public key here
 
 
 public static String encrypt(String data) {
  return b64(encrpyt(data.getBytes()));
 }
 
 public static byte[] encrpyt(byte[] data) {
  genKey();
  try {
   Cipher c1 = Cipher.getInstance(alg[1]);
         c1.init(Cipher.ENCRYPT_MODE, getServPub());
         return c1.doFinal(data);
  } catch(Exception e) {
   Log.e(tag, "encrpyt", e);
  }
  return new byte[0];
 }
 
 public static void genKey() {
  if (privKey == null || pubKey == null) {
   Log.i(tag, "generating key");
   try {
    KeyPairGenerator kpg = KeyPairGenerator.getInstance(alg[0]);
    kpg.initialize(1024);
    KeyPair kp = kpg.generateKeyPair();
    privKey = kp.getPrivate();
    pubKey = kp.getPublic();
   } catch (Exception e) {
    Log.e(tag, "genKey", e);
   }
  }
 }
 
 public static PublicKey getServPub() {
  if(servPub == null) {
   try {
    byte[] encodedPublicKey = b64decode(serverPubKeyB64);
    
    KeyFactory keyFactory = KeyFactory.getInstance(alg[0]);
    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedPublicKey);
    PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
    
    return publicKey;
   } catch(Exception e) {
    Log.e(tag, "getServPub", e);
   }
  }
  return servPub;
 }
 
 public static PublicKey getPubKey() {
  genKey();
  return pubKey;
 }
 
 public static String getPubKeyB64() {
  PublicKey key = getPubKey();
  if(key != null) {
   return b64(getPubKey().getEncoded());
  } else {
   Log.e(tag, "getPubKeyB64 - key is null");
   return "";
  }
 }
 
 public static String b64(byte[] b) {
  return Base64.encodeToString(b, Base64.DEFAULT);
 }
 
 public static byte[] b64decode(String str) {
  return Base64.decode(str, Base64.DEFAULT);
 }
 
 public static String sha1(String data) {
  return sha1(data.getBytes());
 }
 
 
 public static String sha1(byte[] data) {
  return formatString(sha1bytes(data));
 }
 
 public static byte[] sha1bytes(byte[] data) {
  try {
   MessageDigest md = MessageDigest.getInstance(hash);
   return md.digest(data);
  } catch(Exception e) {
   Log.e(tag, "sha1", e);
   return new byte[0];
  }
 }
 
 @SuppressLint("DefaultLocale")
 public static String formatString(byte[] data) {
  StringBuilder sb = new StringBuilder();

  for (byte b : data) {
      sb.append(String.format("%02X", b));
  }
  
  return sb.toString().toLowerCase();
 }
}
And the PHP code:
class Encryption {

    public $pubkey = '...';

    public $privkey;
 
 public function __construct() {
  $this->privkey = openssl_pkey_get_private(file_get_contents('....pem'));
 }

    public function encrypt($data) {
        if (openssl_public_encrypt($data, $encrypted, $this->pubkey))
            $data = base64_encode($encrypted);
        else
            throw new Exception('Unable to encrypt data.');

        return $data;
    }

    public function decrypt($data) {
        if (openssl_private_decrypt(base64_decode($data), $decrypted, $this->privkey))
            $data = $decrypted;
        else
            $data = '';

        return $data;
    }
}