/* * Copyright 2011 yingxinwu.g@gmail.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package xink.crypto.test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.List; import xink.crypto.StreamCrypto; import xink.vpn.wrapper.L2tpProfile; import xink.vpn.wrapper.PptpProfile; import xink.vpn.wrapper.VpnProfile; import xink.vpn.wrapper.VpnType; import android.test.AndroidTestCase; /** * 字节流加解密的测试 * * @author ywu * */ public class StreamCryptoTest extends AndroidTestCase { private String segment = "0123456789abcdef"; // 新的密钥保存方法应能还原老版本的备份文件 private final String EXP_BAK_ID = "ee6edc7c-0a05-49b2-9a83-5b87130209b8"; private final String EXP_BAK_1_NAME = "pptp"; private final String EXP_BAK_1_SERVER = "192.168.10.100"; private final boolean EXP_BAK_1_ENCRYPT = false; private final String EXP_BAK_1_DNS = "8.8.8.8"; private final String EXP_BAK_1_USR = "usr"; private final String EXP_BAK_1_PASSWD = "psw"; private final String EXP_BAK_2_NAME = "l2tp"; private final String EXP_BAK_2_SERVER = "192.168.10.101"; private final boolean EXP_BAK_2_ENCRYPT = false; private final String EXP_BAK_2_DNS = "8.8.8.8"; private final String EXP_BAK_2_USR = "usr"; private final String EXP_BAK_2_PASSWD = "psw"; /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { StreamCrypto.init(mContext); } /** * 测试加解密文本 */ public void testTextCrypto() throws Exception { textCrypto(0); textCrypto(1); textCrypto(8); // 128 bytes textCrypto(9); } private void textCrypto(final int copy) throws Exception { System.out.println("textCrypto, segment copies is " + copy); StringBuilder buf = new StringBuilder(); for (int i = 0; i < copy; i++) { buf.append(segment); } String clearText = buf.toString(); byte[] cipherText = encrpt(clearText); String resultText = decrpt(cipherText); assertEquals("fails when segment copies is " + copy, clearText, resultText); } private byte[] encrpt(final String clearText) throws Exception { ByteArrayInputStream in = new ByteArrayInputStream(clearText.getBytes()); ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamCrypto.encrypt(in, out); byte[] cipherText = out.toByteArray(); System.out.println('\'' + clearText + "' --> " + printBytes(cipherText)); return cipherText; } private String decrpt(final byte[] cipherText) throws Exception { ByteArrayInputStream in = new ByteArrayInputStream(cipherText); ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamCrypto.decrypt(in, out); return new String(out.toByteArray()); } private static String printBytes(final byte[] bytes) { StringBuilder buf = new StringBuilder(); for (byte b : bytes) { buf.append(Integer.toHexString(b)); } return buf.toString(); } /** * 测试对象流加解密 */ public void testObjectStreamCrypto() throws Exception { Data d = new Data(); d.id = 1; d.ts = new Date(); d.value = "v1"; byte[] cipherText = encryptObject(d); Data resultObj = decryptObject(cipherText); assertEquals(d, resultObj); } /** * 测试null对象加解密的情况 */ public void testNullObjectCrypto() throws Exception { byte[] cipherText = encryptObject(null); Data resultObj = decryptObject(cipherText); assertNull(resultObj); } private byte[] encryptObject(final Serializable obj) throws Exception { byte[] objBytes = obj2bytes(obj); ByteArrayInputStream in = new ByteArrayInputStream(objBytes); ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamCrypto.encrypt(in, out); byte[] cipherText = out.toByteArray(); System.out.println(obj + " --> " + printBytes(cipherText)); return cipherText; } private Data decryptObject(final byte[] cipherText) throws Exception { ByteArrayInputStream in = new ByteArrayInputStream(cipherText); ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamCrypto.decrypt(in, out); Data d = (Data) bytes2obj(out.toByteArray()); return d; } private static byte[] obj2bytes(final Serializable d) throws Exception { ByteArrayOutputStream bytes = new ByteArrayOutputStream(); ObjectOutputStream producer = new ObjectOutputStream(bytes); producer.writeObject(d); return bytes.toByteArray(); } private static Serializable bytes2obj(final byte[] bytes) throws Exception { ByteArrayInputStream in = new ByteArrayInputStream(bytes); ObjectInputStream consumer = new ObjectInputStream(in); Serializable d = (Serializable) consumer.readObject(); return d; } /** * 保证能够解密3.1之前的版本加密的数据文件 */ public void testDecryptLagecyActiveIdFile() throws Exception { String activeId = (String) loadLegacyDataFile("old_active_profile_id").readObject(); assertEquals("should restore active-profile-id correctly", EXP_BAK_ID, activeId); } /** * 保证能够解密3.1之前的版本加密的数据文件 */ public void testDecryptLagecyProfilesFile() throws Exception { ObjectInputStream ois = loadLegacyDataFile("old_profiles"); List<VpnProfile> profiles = loadProfilesFrom(ois); assertEquals(2, profiles.size()); VpnProfile p1 = profiles.get(0); assertEquals(VpnType.PPTP, p1.getType()); assertEquals(EXP_BAK_1_NAME, p1.getName()); assertEquals(EXP_BAK_1_SERVER, p1.getServerName()); assertEquals(EXP_BAK_1_ENCRYPT, ((PptpProfile) p1).isEncryptionEnabled()); assertEquals(EXP_BAK_1_USR, p1.getUsername()); assertEquals(EXP_BAK_1_PASSWD, p1.getPassword()); assertEquals(EXP_BAK_1_DNS, p1.getDomainSuffices()); VpnProfile p2 = profiles.get(1); assertEquals(VpnType.L2TP, p2.getType()); assertEquals(EXP_BAK_2_NAME, p2.getName()); assertEquals(EXP_BAK_2_SERVER, p2.getServerName()); assertEquals(EXP_BAK_2_ENCRYPT, ((L2tpProfile) p2).isSecretEnabled()); assertEquals(EXP_BAK_2_USR, p2.getUsername()); assertEquals(EXP_BAK_2_PASSWD, p2.getPassword()); assertEquals(EXP_BAK_2_DNS, p2.getDomainSuffices()); } private ObjectInputStream loadLegacyDataFile(final String file) throws Exception { InputStream in = getClass().getResourceAsStream(file); assertNotNull(in); ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamCrypto.decrypt(in, out); byte[] data = out.toByteArray(); return new ObjectInputStream(new ByteArrayInputStream(data)); } private List<VpnProfile> loadProfilesFrom(final ObjectInputStream is) throws Exception { List<VpnProfile> profiles = new ArrayList<VpnProfile>(); try { while (true) { VpnType type = (VpnType) is.readObject(); Object obj = is.readObject(); assertNotNull(obj); VpnProfile p = VpnProfile.newInstance(type, mContext); if (p.isCompatible(obj)) { p.read(obj, is); profiles.add(p); } else { fail("saved profile '" + obj + "' is NOT compatible with " + type); } } } catch (EOFException eof) { // reach end of file } return profiles; } } /** * 用于测试的数据对象 */ class Data implements Serializable { private static final long serialVersionUID = 1L; int id; Date ts; String value; @Override public boolean equals(final Object obj) { if (obj == this) return true; if (!(obj instanceof Data)) return false; Data that = (Data) obj; return this.id == that.id && this.ts.equals(that.ts) && this.value.equals(that.value); } }