src/net/java/otr4j/OtrKeyManagerImpl.java
changeset 895 b2e1b45382a4
parent 810 0ff0059f2ec3
child 900 ab30d289a86c
equal deleted inserted replaced
894:5315a5713dd5 895:b2e1b45382a4
       
     1 package net.java.otr4j;
       
     2 
       
     3 import java.io.BufferedInputStream;
       
     4 import java.io.File;
       
     5 import java.io.FileInputStream;
       
     6 import java.io.FileNotFoundException;
       
     7 import java.io.FileOutputStream;
       
     8 import java.io.IOException;
       
     9 import java.io.InputStream;
       
    10 import java.io.OutputStream;
       
    11 import java.security.KeyFactory;
       
    12 import java.security.KeyPair;
       
    13 import java.security.KeyPairGenerator;
       
    14 import java.security.NoSuchAlgorithmException;
       
    15 import java.security.PrivateKey;
       
    16 import java.security.PublicKey;
       
    17 import java.security.spec.InvalidKeySpecException;
       
    18 import java.security.spec.PKCS8EncodedKeySpec;
       
    19 import java.security.spec.X509EncodedKeySpec;
       
    20 import java.util.List;
       
    21 import java.util.Properties;
       
    22 import java.util.Vector;
       
    23 
       
    24 import org.bouncycastle2.util.encoders.Base64;
       
    25 
       
    26 import net.java.otr4j.crypto.OtrCryptoEngineImpl;
       
    27 import net.java.otr4j.crypto.OtrCryptoException;
       
    28 import net.java.otr4j.session.SessionID;
       
    29 
       
    30 public class OtrKeyManagerImpl implements OtrKeyManager {
       
    31 
       
    32 	private OtrKeyManagerStore store;
       
    33 
       
    34 	public OtrKeyManagerImpl(OtrKeyManagerStore store) {
       
    35 		this.store = store;
       
    36 	}
       
    37 
       
    38 	class DefaultPropertiesStore implements OtrKeyManagerStore {
       
    39 		private final Properties properties = new Properties();
       
    40 		private String filepath;
       
    41 
       
    42 		public DefaultPropertiesStore(String filepath) throws IOException {
       
    43 			if (filepath == null || filepath.length() < 1)
       
    44 				throw new IllegalArgumentException();
       
    45 			this.filepath = filepath;
       
    46 			properties.clear();
       
    47 
       
    48 			InputStream in = new BufferedInputStream(new FileInputStream(
       
    49 					getConfigurationFile()));
       
    50 			try {
       
    51 				properties.load(in);
       
    52 			} finally {
       
    53 				in.close();
       
    54 			}
       
    55 		}
       
    56 
       
    57 		private File getConfigurationFile() throws IOException {
       
    58 			File configFile = new File(filepath);
       
    59 			if (!configFile.exists())
       
    60 				configFile.createNewFile();
       
    61 			return configFile;
       
    62 		}
       
    63 
       
    64 		public void setProperty(String id, boolean value) {
       
    65 			properties.setProperty(id, "true");
       
    66 			try {
       
    67 				this.store();
       
    68 			} catch (Exception e) {
       
    69 				e.printStackTrace();
       
    70 			}
       
    71 		}
       
    72 
       
    73 		private void store() throws FileNotFoundException, IOException {
       
    74 			OutputStream out = new FileOutputStream(getConfigurationFile());
       
    75 			properties.store(out, null);
       
    76 			out.close();
       
    77 		}
       
    78 
       
    79 		public void setProperty(String id, byte[] value) {
       
    80 			properties.setProperty(id, new String(Base64.encode(value)));
       
    81 			try {
       
    82 				this.store();
       
    83 			} catch (Exception e) {
       
    84 				e.printStackTrace();
       
    85 			}
       
    86 		}
       
    87 
       
    88 		public void removeProperty(String id) {
       
    89 			properties.remove(id);
       
    90 
       
    91 		}
       
    92 
       
    93 		public byte[] getPropertyBytes(String id) {
       
    94 			String value = properties.getProperty(id);
       
    95 			return Base64.decode(value);
       
    96 		}
       
    97 
       
    98 		public boolean getPropertyBoolean(String id, boolean defaultValue) {
       
    99 			try {
       
   100 				return Boolean.valueOf(properties.get(id).toString());
       
   101 			} catch (Exception e) {
       
   102 				return defaultValue;
       
   103 			}
       
   104 		}
       
   105 	}
       
   106 
       
   107 	public OtrKeyManagerImpl(String filepath) throws IOException {
       
   108 		this.store = new DefaultPropertiesStore(filepath);
       
   109 	}
       
   110 
       
   111 	private List<OtrKeyManagerListener> listeners = new Vector<OtrKeyManagerListener>();
       
   112 
       
   113 	public void addListener(OtrKeyManagerListener l) {
       
   114 		synchronized (listeners) {
       
   115 			if (!listeners.contains(l))
       
   116 				listeners.add(l);
       
   117 		}
       
   118 	}
       
   119 
       
   120 	public void removeListener(OtrKeyManagerListener l) {
       
   121 		synchronized (listeners) {
       
   122 			listeners.remove(l);
       
   123 		}
       
   124 	}
       
   125 
       
   126 	public void generateLocalKeyPair(SessionID sessionID) {
       
   127 		if (sessionID == null)
       
   128 			return;
       
   129 
       
   130 		String accountID = sessionID.getAccountID();
       
   131 		KeyPair keyPair;
       
   132 		try {
       
   133 			keyPair = KeyPairGenerator.getInstance("DSA").genKeyPair();
       
   134 		} catch (NoSuchAlgorithmException e) {
       
   135 			e.printStackTrace();
       
   136 			return;
       
   137 		}
       
   138 
       
   139 		// Store Public Key.
       
   140 		PublicKey pubKey = keyPair.getPublic();
       
   141 		X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(pubKey
       
   142 				.getEncoded());
       
   143 
       
   144 		this.store.setProperty(accountID + ".publicKey", x509EncodedKeySpec
       
   145 				.getEncoded());
       
   146 
       
   147 		// Store Private Key.
       
   148 		PrivateKey privKey = keyPair.getPrivate();
       
   149 		PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
       
   150 				privKey.getEncoded());
       
   151 
       
   152 		this.store.setProperty(accountID + ".privateKey", pkcs8EncodedKeySpec
       
   153 				.getEncoded());
       
   154 	}
       
   155 
       
   156 	public String getLocalFingerprint(SessionID sessionID) {
       
   157 		KeyPair keyPair = loadLocalKeyPair(sessionID);
       
   158 
       
   159 		if (keyPair == null)
       
   160 			return null;
       
   161 
       
   162 		PublicKey pubKey = keyPair.getPublic();
       
   163 
       
   164 		try {
       
   165 			return new OtrCryptoEngineImpl().getFingerprint(pubKey);
       
   166 		} catch (OtrCryptoException e) {
       
   167 			e.printStackTrace();
       
   168 			return null;
       
   169 		}
       
   170 	}
       
   171 
       
   172 	public String getRemoteFingerprint(SessionID sessionID) {
       
   173 		PublicKey remotePublicKey = loadRemotePublicKey(sessionID);
       
   174 		if (remotePublicKey == null)
       
   175 			return null;
       
   176 		try {
       
   177 			return new OtrCryptoEngineImpl().getFingerprint(remotePublicKey);
       
   178 		} catch (OtrCryptoException e) {
       
   179 			e.printStackTrace();
       
   180 			return null;
       
   181 		}
       
   182 	}
       
   183 
       
   184 	public boolean isVerified(SessionID sessionID) {
       
   185 		if (sessionID == null)
       
   186 			return false;
       
   187 
       
   188 		return this.store.getPropertyBoolean(sessionID.getUserID()
       
   189 				+ ".publicKey.verified", false);
       
   190 	}
       
   191 
       
   192 	public KeyPair loadLocalKeyPair(SessionID sessionID) {
       
   193 		if (sessionID == null)
       
   194 			return null;
       
   195 
       
   196 		String accountID = sessionID.getAccountID();
       
   197 		// Load Private Key.
       
   198 		byte[] b64PrivKey = this.store.getPropertyBytes(accountID
       
   199 				+ ".privateKey");
       
   200 		if (b64PrivKey == null)
       
   201 			return null;
       
   202 
       
   203 		PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(b64PrivKey);
       
   204 
       
   205 		// Load Public Key.
       
   206 		byte[] b64PubKey = this.store
       
   207 				.getPropertyBytes(accountID + ".publicKey");
       
   208 		if (b64PubKey == null)
       
   209 			return null;
       
   210 
       
   211 		X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(b64PubKey);
       
   212 
       
   213 		PublicKey publicKey;
       
   214 		PrivateKey privateKey;
       
   215 
       
   216 		// Generate KeyPair.
       
   217 		KeyFactory keyFactory;
       
   218 		try {
       
   219 			keyFactory = KeyFactory.getInstance("DSA");
       
   220 			publicKey = keyFactory.generatePublic(publicKeySpec);
       
   221 			privateKey = keyFactory.generatePrivate(privateKeySpec);
       
   222 		} catch (NoSuchAlgorithmException e) {
       
   223 			e.printStackTrace();
       
   224 			return null;
       
   225 		} catch (InvalidKeySpecException e) {
       
   226 			e.printStackTrace();
       
   227 			return null;
       
   228 		}
       
   229 
       
   230 		return new KeyPair(publicKey, privateKey);
       
   231 	}
       
   232 
       
   233 	public PublicKey loadRemotePublicKey(SessionID sessionID) {
       
   234 		if (sessionID == null)
       
   235 			return null;
       
   236 
       
   237 		String userID = sessionID.getUserID();
       
   238 
       
   239 		byte[] b64PubKey = this.store.getPropertyBytes(userID + ".publicKey");
       
   240 		if (b64PubKey == null)
       
   241 			return null;
       
   242 
       
   243 		X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(b64PubKey);
       
   244 
       
   245 		// Generate KeyPair.
       
   246 		KeyFactory keyFactory;
       
   247 		try {
       
   248 			keyFactory = KeyFactory.getInstance("DSA");
       
   249 			return keyFactory.generatePublic(publicKeySpec);
       
   250 		} catch (NoSuchAlgorithmException e) {
       
   251 			e.printStackTrace();
       
   252 			return null;
       
   253 		} catch (InvalidKeySpecException e) {
       
   254 			e.printStackTrace();
       
   255 			return null;
       
   256 		}
       
   257 	}
       
   258 
       
   259 	public void savePublicKey(SessionID sessionID, PublicKey pubKey) {
       
   260 		if (sessionID == null)
       
   261 			return;
       
   262 
       
   263 		X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(pubKey
       
   264 				.getEncoded());
       
   265 
       
   266 		String userID = sessionID.getUserID();
       
   267 		this.store.setProperty(userID + ".publicKey", x509EncodedKeySpec
       
   268 				.getEncoded());
       
   269 
       
   270 		this.store.removeProperty(userID + ".publicKey.verified");
       
   271 	}
       
   272 
       
   273 	public void unverify(SessionID sessionID) {
       
   274 		if (sessionID == null)
       
   275 			return;
       
   276 
       
   277 		if (!isVerified(sessionID))
       
   278 			return;
       
   279 
       
   280 		this.store
       
   281 				.removeProperty(sessionID.getUserID() + ".publicKey.verified");
       
   282 
       
   283 		for (OtrKeyManagerListener l : listeners)
       
   284 			l.verificationStatusChanged(sessionID);
       
   285 
       
   286 	}
       
   287 
       
   288 	public void verify(SessionID sessionID) {
       
   289 		if (sessionID == null)
       
   290 			return;
       
   291 
       
   292 		if (this.isVerified(sessionID))
       
   293 			return;
       
   294 
       
   295 		this.store.setProperty(sessionID.getUserID() + ".publicKey.verified",
       
   296 				true);
       
   297 
       
   298 		for (OtrKeyManagerListener l : listeners)
       
   299 			l.verificationStatusChanged(sessionID);
       
   300 	}
       
   301 
       
   302 }