// -*- mode: java; c-basic-offset: 2; -*- // Copyright 2009-2011 Google, All Rights reserved // Copyright 2011-2012 MIT, All rights reserved // Released under the Apache License, Version 2.0 // http://www.apache.org/licenses/LICENSE-2.0 package com.google.appinventor.server.encryption; import com.google.appinventor.server.flags.Flag; import com.google.common.annotations.VisibleForTesting; import org.keyczar.Crypter; import org.keyczar.exceptions.KeyczarException; /* * We currently use only one key for development and production. The * expectation is that this key will be generated in directory called * keystore (commands for doing this are described in the README in * the keyczar directory). The key directory should be placed in the * war directory (at the same level as WEB-INF), so it can be accessed * as a resource, and the appengine-web.xml file will need to have the * following in it: * <static-files> * <exclude path="/keystore/**" /> * </static-files> * to prevent it from being accessed as a static file (so that it * cannot be downloaded by random users referencing it as a url. */ /** * Encrypts/decrypts byte arrays using Keyczar * * @author kerr@google.com (Debby Wallach) */ @VisibleForTesting public class KeyczarEncryptor implements Encryptor { // When running on appengine, the application is running in a way that // the rootPath should not be set to anything. This flag needs to be // set for testing. @VisibleForTesting public static final Flag<String> rootPath = Flag.createFlag("root.path", ""); private Crypter crypter = null; // accessed through getCrypter only private static final Object crypterSync = new Object(); /** * {@inheritDoc} * * <p>Uses Keyczar client to encrypt the byte array. * * @throws EncryptionException if any underlying component fails */ @Override public byte[] encrypt(byte[] plain) throws EncryptionException { try { Crypter crypter = getCrypter(); return crypter.encrypt(plain); } catch (KeyczarException e) { throw new EncryptionException(e); } } /** * {@inheritDoc} * * <p>Uses local Keyczar client to decrypt the byte array. * * @throws EncryptionException if any underlying component fails */ @Override public byte[] decrypt(byte[] encrypted) throws EncryptionException { try { Crypter crypter = getCrypter(); return crypter.decrypt(encrypted); } catch (KeyczarException e) { throw new EncryptionException(e); } } /* Currently uses the same key for development and deployment. */ private Crypter getCrypter() throws EncryptionException { synchronized (crypterSync) { if (crypter != null) { return crypter; } try { // TODO(user): Should we use a different key for development vs deployment? String pathToKeys = rootPath.get() + "keystore"; crypter = new Crypter(pathToKeys); return crypter; } catch (KeyczarException e) { throw new EncryptionException(e); } } } }