113 lines · 3.8 KB · Java
RawDownload
package plan9.ssl; import java.util.Arrays; import java.io.IOException;import java.nio.channels.ReadableByteChannel;import java.nio.channels.WritableByteChannel;import java.nio.channels.ByteChannel;import java.nio.ByteBuffer; import java.security.NoSuchAlgorithmException; import plan9.Log;import plan9.LogFactory; import plan9.lib.Misc;import plan9.lib.Base16;import plan9.lib.Base64;import plan9.auth.Aids;import plan9.auth.AuthenticationException;import plan9.auth.CryptoError; // "LineCrypt" is not a good name: think of a better onepublic class LineCrypt { 	static final Base16 b16 = new Base16();	static final Base64 b64 = new Base64(); 	static final Log log = LogFactory.logger(LineCrypt.class); 	public static final Ssl sslserver(ReadableByteChannel rfd, WritableByteChannel wfd, byte[] secret) throws NoSuchAlgorithmException, CryptoError, IOException { 		byte[]	key = new byte[128/8];		byte[]	digest = new byte[Aids.SHA1dlen];		byte[]	fromclientsecret = new byte[Aids.SHA1dlen/2];		byte[]	fromserversecret = new byte[Aids.SHA1dlen/2]; 		if(log.debugging())			log.debug("server master-secret %s", Misc.dump(secret)); 		int n = key.length - 4;		if(n > secret.length)			n = secret.length;		Arrays.fill(key, (byte)0xFF);		System.arraycopy(secret, 0, key, 4, n); 		// exchange random numbers		Aids.memrandom(key, 12, 4);		wfd.write(ByteBuffer.wrap(key, 12, 4));		if(Misc.readn(rfd, key, 0, 4) == null)			throw new IOException("sslserver: unexpected end-of-file"); 		// scramble into two secrets		Aids.sha1(key, digest);		System.arraycopy(digest, 0, fromclientsecret, 0, fromclientsecret.length);		System.arraycopy(digest, fromclientsecret.length, fromserversecret, 0, fromserversecret.length);		// set up encryption		return Ssl.push(rfd, wfd, "rc4", cvkey(fromserversecret), cvkey(fromclientsecret));	} 	public static final Ssl sslserver(ByteChannel fd, byte[] secret) throws NoSuchAlgorithmException, CryptoError, IOException {		return sslserver(fd, fd, secret);	} 	public static final Ssl sslclient(ReadableByteChannel rfd, WritableByteChannel wfd, byte[] secret) throws NoSuchAlgorithmException, CryptoError, IOException { 		byte[]	key = new byte[128/8];		byte[]	digest = new byte[Aids.SHA1dlen];		byte[]	fromclientsecret = new byte[Aids.SHA1dlen/2];		byte[]	fromserversecret = new byte[Aids.SHA1dlen/2]; 		if(log.debugging())			log.debug("client master-secret %s", Misc.dump(secret)); 		int n = key.length - 4;		if(n > secret.length)			n = secret.length;		Arrays.fill(key, (byte)0xFF);		System.arraycopy(secret, 0, key, 4, n); 		// exchange random numbers		Aids.memrandom(key, 0, 4);		wfd.write(ByteBuffer.wrap(key, 0, 4));		if(Misc.readn(rfd, key, 12, 4) == null)			throw new IOException("sslclient: unexpected end-of-file"); 		// scramble into two secrets		Aids.sha1(key, digest);		System.arraycopy(digest, 0, fromclientsecret, 0, fromclientsecret.length);		System.arraycopy(digest, fromclientsecret.length, fromserversecret, 0, fromserversecret.length); 		// set up encryption		return Ssl.push(rfd, wfd, "rc4", cvkey(fromclientsecret), cvkey(fromserversecret));	} 	public static final Ssl sslclient(ByteChannel fd, byte[] secret) throws NoSuchAlgorithmException, CryptoError, IOException {		return sslclient(fd, fd, secret);	} 	// Plan 9's import/export protocol takes the key parts above, converts to lower-case hex, and	// passes them to ssl(3) or tls(3)'s control file as "secretin" and "secretout", interpreted as base64 encodings.	// Do the same here to get the right encryption key.	static final byte[] cvkey(byte[] key){		return b64.dec(hex(key));	} 	static final String hex(byte[] a){		StringBuilder bs = new StringBuilder(64);		for(int i = 0; i < a.length; i++)			bs.append(String.format("%02x", (int)a[i] & 0xFF));	// lower case, unlike Base16.enc		return bs.toString();	}}