Archive for category My Code

Post-Redirect-Get in Rails

For a while now I’ve been flying the flag for using a post-redirect-get design pattern when writing web applications. In my opinion the current crop of web frameworks still make it very easy to do the “bad” thing since to do PRG properly you need to think what kind of an interaction you want with users and not cop out saying its technically very difficult in <insert framework here>. If you resort to ActiveX controls, popups without navigation bars and/or weird javascript hacks to stop users from clicking refresh or back buttons then perhaps you should have written a better web application.

Whenever I play with Rails, or for that matter any other web framework, I get stuck on trying to find a problem to solve (or a set of requirements). Fortunately the Agile Development with Rails book from the Pragmatic Programmers has a nice little bookstore application that I can develop iteratively. I’ve put my latest adaptation of their depot application to use post-redirect-get (even works with ActiveResource scaffolds), UUIDs as ActiveRecord primary keys, HAML, SASS and RSpec on GitHub. Feedback is always welcome.

Tags: , , , , , , , ,

PicoContainer and Jersey

The Jersey JAX-RS project provides bindings for springframework and google-guice. However I wanted to see what it would take to use PicoContainer as an IoC container within Jersey.

Verdict: not much at all. Nicely extensible.

To see what I mean please take a look at my jersey-pico project on GitHub. I can now create JAX-RS services in Java or Groovy with a very simple IoC container.

Tags: , , , , , , ,

Java and iPhone AES interoperability

I’ve been trying to get my head around cryptography on the iPhone so that I can create a native iPhone app (iPasskeep) that interoperates with my JPasskeep password keeper application. It has taken a while to get my head around CommonCrypto APIs – how to use them, how not to use them and their limitations. It then took a bit of fiddling to find the right incantations in Java to get an interoperable cryptographic transformation.

Caveat: The following Objective-C code is not yet production ready or quality. It passes unit tests, but I haven’t checked it for memory leaks, performance, etc.

Hope this helps.

Listing: Cipher.h

#import <Cocoa/Cocoa.h>

#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>

@interface Cipher : NSObject {
	NSString* cipherKey;
}

@property (retain) NSString* cipherKey;

- (Cipher *) initWithKey:(NSString *) key;

- (NSData *) encrypt:(NSData *) plainText;
- (NSData *) decrypt:(NSData *) cipherText;

- (NSData *) transform:(CCOperation) encryptOrDecrypt data:(NSData *) inputData;

+ (NSData *) md5:(NSString *) stringToHash;

@end

Listing: Cipher.m

#import "Cipher.h"

@implementation Cipher

@synthesize cipherKey;

- (Cipher *) initWithKey:(NSString *) key {
	self = [super init];
	if (self) {
		[self setCipherKey:key];
	}
	return self;
}

- (NSData *) encrypt:(NSData *) plainText {
	return [self transform:kCCEncrypt data:plainText];
}

- (NSData *) decrypt:(NSData *) cipherText {
	return [self transform:kCCDecrypt data:cipherText];
}

- (NSData *) transform:(CCOperation) encryptOrDecrypt data:(NSData *) inputData {

	// kCCKeySizeAES128 = 16 bytes
	// CC_MD5_DIGEST_LENGTH = 16 bytes
	NSData* secretKey = [Cipher md5:cipherKey];

	CCCryptorRef cryptor = NULL;
	CCCryptorStatus status = kCCSuccess;

	uint8_t iv[kCCBlockSizeAES128];
    memset((void *) iv, 0x0, (size_t) sizeof(iv));

	status = CCCryptorCreate(encryptOrDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
							 [secretKey bytes], kCCKeySizeAES128, iv, &cryptor);

	if (status != kCCSuccess) {
		return nil;
	}

	size_t bufsize = CCCryptorGetOutputLength(cryptor, (size_t)[inputData length], true);

	void * buf = malloc(bufsize * sizeof(uint8_t));
	memset(buf, 0x0, bufsize);

	size_t bufused = 0;
    size_t bytesTotal = 0;

	status = CCCryptorUpdate(cryptor, [inputData bytes], (size_t)[inputData length],
							 buf, bufsize, &bufused);

	if (status != kCCSuccess) {
		free(buf);
		CCCryptorRelease(cryptor);
		return nil;
	}

	bytesTotal += bufused;

	status = CCCryptorFinal(cryptor, buf + bufused, bufsize - bufused, &bufused);

	if (status != kCCSuccess) {
		free(buf);
		CCCryptorRelease(cryptor);
		return nil;
	}

	bytesTotal += bufused;

	CCCryptorRelease(cryptor);

	return [NSData dataWithBytesNoCopy:buf length:bytesTotal];
}

+ (NSData *) md5:(NSString *) stringToHash {

	const char *src = [stringToHash UTF8String];

	unsigned char result[CC_MD5_DIGEST_LENGTH];

	CC_MD5(src, strlen(src), result);

	return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH];
}

@end

Listing: Cipher.java

package com.tomczarniecki.iphone;

import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

public class Cipher {

    private final String password;

    public Cipher(String password) {
        this.password = password;
    }

    public byte[] encrypt(byte[] plainText) throws Exception {
        return transform(true, plainText);
    }

    public byte[] decrypt(byte[] cipherText) throws Exception {
        return transform(false, cipherText);
    }

    private byte[] transform(boolean encrypt, byte[] inputBytes) throws Exception {
        byte[] key = DigestUtils.md5(password.getBytes("UTF-8"));

        BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
        cipher.init(encrypt, new KeyParameter(key));

        ByteArrayInputStream input = new ByteArrayInputStream(inputBytes);
        ByteArrayOutputStream output = new ByteArrayOutputStream();

        int inputLen;
        int outputLen;

        byte[] inputBuffer = new byte[1024];
        byte[] outputBuffer = new byte[cipher.getOutputSize(inputBuffer.length)];

        while ((inputLen = input.read(inputBuffer)) > -1) {
            outputLen = cipher.processBytes(inputBuffer, 0, inputLen, outputBuffer, 0);
            if (outputLen > 0) {
                output.write(outputBuffer, 0, outputLen);
            }
        }

        outputLen = cipher.doFinal(outputBuffer, 0);
        if (outputLen > 0) {
            output.write(outputBuffer, 0, outputLen);
        }

        return output.toByteArray();
    }
}

Tags: , , , , , ,