@Test public void toByteArrayAndBack() { byte[] arrayA = packet.toByteArray(); byte[] arrayB = new UnencryptedEmailPacket(arrayA).toByteArray(); assertArrayEquals("The two arrays differ!", arrayA, arrayB); } }
private String getFilename(UnencryptedEmailPacket packet) { String fragIndex = String.format("%03d", packet.getFragmentIndex()); return packet.getMessageId() + "_" + fragIndex + PacketFolder.PACKET_FILE_EXTENSION; }
/** * Sets the number of packets the email was fragmented into. * @param numFragments */ public void setNumFragments(int numFragments) { this.numFragments = numFragments; verify(); }
private EncryptedEmailPacket makeEmailPacket(String message) throws GeneralSecurityException, I2PSessionException, IOException { byte[] content = message.getBytes(); byte[] messageIdBytes = new byte[] {6, -32, -23, 17, 55, 15, -45, -19, 91, 100, -76, -76, 118, -118, -53, -109, -108, 113, -112, 81, 117, 9, -126, 20, 0, -83, -89, 7, 48, 76, -58, 83}; UniqueId messageId = new UniqueId(messageIdBytes, 0); int fragmentIndex = 0; UnencryptedEmailPacket plaintextPacket = new UnencryptedEmailPacket(new ByteArrayInputStream(content), messageId, fragmentIndex, I2PBotePacket.MAX_DATAGRAM_SIZE); plaintextPacket.setNumFragments(1); return new EncryptedEmailPacket(plaintextPacket, identity); }
/** * Creates an <code>EncryptedEmailPacket</code> from an <code>UnencryptedEmailPacket</code>. * The public key of <code>emailDestination</code> is used for encryption. * The store time is set to <code>0</code>. * @param unencryptedPacket * @param emailDestination * @throws GeneralSecurityException If an error occurred during encryption */ public EncryptedEmailPacket(UnencryptedEmailPacket unencryptedPacket, EmailDestination emailDestination) throws GeneralSecurityException { storeTime = 0; byte[] delAuthorizationBytes = unencryptedPacket.getDeleteAuthorization().toByteArray(); delVerificationHash = SHA256Generator.getInstance().calculateHash(delAuthorizationBytes); cryptoImpl = emailDestination.getCryptoImpl(); encryptedData = cryptoImpl.encrypt(unencryptedPacket.toByteArray(), emailDestination.getPublicEncryptionKey()); dhtKey = getDhtKey(); }
@Test public void testCreateEmailPackets() throws MessagingException, IOException, GeneralSecurityException, SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException, PasswordException { // convert an email to a byte array, convert back, and compare with the original email for (Email email: emails) { EmailIdentity identity = identities.get(email); KeyUpdateHandler keyUpdateHandler = TestUtil.createDummyKeyUpdateHandler(); Collection<UnencryptedEmailPacket> packets = email.createEmailPackets(identity, keyUpdateHandler, null, I2PBotePacket.MAX_DATAGRAM_SIZE); assertTrue("Expected more email packets. #packets = " + packets.size(), packets.size() > email.getText().length()/I2PBotePacket.MAX_DATAGRAM_SIZE/2); // the emails are somewhat compressible, but definitely not by 50% ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); for (UnencryptedEmailPacket packet: packets) outputStream.write(packet.getContent()); Email newEmail = new Email(outputStream.toByteArray()); assertEquals(email.getContent(), newEmail.getContent()); // check packet sizes against size limit for (UnencryptedEmailPacket packet: packets) assertTrue("Email packet exceeds max size!", packet.toByteArray().length <= I2PBotePacket.MAX_DATAGRAM_SIZE); } }
indexPacketDeleteRequest.put(emailPacketKey, decryptedPacket.getDeleteAuthorization()); UniqueId delAuthorization = decryptedPacket.getDeleteAuthorization(); sendDeleteRequest(emailPacketKey, delAuthorization, peer);
@Test public void testEncryptionDecryption() throws Exception { for (int i=0; i<encryptedPackets.length; i++) { EncryptedEmailPacket packet = encryptedPackets[i]; UnencryptedEmailPacket decryptedPacket = packet.decrypt(identities[i]); byte[] arrayA = decryptedPacket.getContent(); byte[] arrayB = message.getBytes(); assertArrayEquals("Email message differs after decryption! CryptoImplementation = " + packet.getCryptoImpl().getName(), arrayA, arrayB); } }
try { for (UnencryptedEmailPacket packet: packets) outputStream.write(packet.getContent()); Email email = new Email(outputStream.toByteArray()); email.setMessageID(packets[0].getMessageId()); // all packets in the array have the same message ID
@Override protected UnencryptedEmailPacket createFolderElement(File file) throws IOException { FileInputStream inputStream = null; try { inputStream = new FileInputStream(file); return new UnencryptedEmailPacket(inputStream); } finally { if (inputStream != null) inputStream.close(); } }
/** * Stores an <code>UnencryptedEmailPacket</code> in the folder and returns <code>true</code> * if an email was completed as a result of adding the packet. * @param packetToStore * @see i2p.bote.folder.PacketFolder#add(I2PBotePacket, String) */ public synchronized boolean addEmailPacket(UnencryptedEmailPacket packetToStore) { UniqueId messageId = packetToStore.getMessageId(); // if a previously assembled (completed) email contained the message ID, ignore the email packet if (messageIdCache.contains(messageId)) { log.debug("Discarding email packet because the message ID matches a previously received email. Packet: " + packetToStore); return false; } add(packetToStore, getFilename(packetToStore)); // TODO possible optimization: if getNumFragments == 1, no need to check for other packet files File[] finishedPacketFiles = getAllMatchingFiles(messageId); // if all packets of the email are available, assemble them into an email if (finishedPacketFiles.length == packetToStore.getNumFragments()) { assemble(finishedPacketFiles); messageIdCache.add(messageId); return true; } return false; }
@Override public int compare(UnencryptedEmailPacket packet1, UnencryptedEmailPacket packet2) { return Integer.valueOf(packet1.getFragmentIndex()).compareTo(packet2.getFragmentIndex()); } });
@Override public byte[] toByteArray() { ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream(); DataOutputStream dataStream = new DataOutputStream(byteArrayStream); try { writeHeader(dataStream); messageId.writeTo(dataStream); delAuthorization.writeTo(dataStream); dataStream.writeShort(fragmentIndex); dataStream.writeShort(numFragments); dataStream.writeShort(content.length); dataStream.write(content); } catch (IOException e) { log.error("Can't write to ByteArrayOutputStream.", e); } return byteArrayStream.toByteArray(); }
EncryptedEmailPacket createEmailPacket(EmailDestination dest, String message) throws Exception { byte[] content = message.getBytes(); byte[] messageIdBytes = new byte[] {-69, -24, -109, 1, 69, -122, -69, 113, -68, -90, 55, -28, 105, 97, 125, 70, 51, 58, 14, 2, -13, -53, 90, -29, 36, 67, 36, -94, -108, -125, 11, 123}; UniqueId messageId = new UniqueId(messageIdBytes, 0); int fragmentIndex = 0; UnencryptedEmailPacket plaintextPacket = new UnencryptedEmailPacket(new ByteArrayInputStream(content), messageId, fragmentIndex, I2PBotePacket.MAX_DATAGRAM_SIZE); plaintextPacket.setNumFragments(1); return new EncryptedEmailPacket(plaintextPacket, dest); }
/** Tests processing of one valid and one invalid {@link EmailPacketDeleteRequest}. */ @Test public void testPacketReceived() throws PasswordException { packetFolder.store(emailPacket); assertEquals(1, packetFolder.getElements().size()); EmailPacketDeleteRequest delRequest; // send an invalid delete request byte[] delAuthBytes = unencryptedPacket.getDeleteAuthorization().toByteArray().clone(); delAuthBytes[5] ^= 1; UniqueId invalidAuthorization = new UniqueId(delAuthBytes, 0); delRequest = new EmailPacketDeleteRequest(emailPacket.getDhtKey(), invalidAuthorization); packetFolder.packetReceived(delRequest, sender, System.currentTimeMillis()); assertEquals(1, packetFolder.getElements().size()); // send a valid delete request delRequest = new EmailPacketDeleteRequest(emailPacket.getDhtKey(), unencryptedPacket.getDeleteAuthorization()); packetFolder.packetReceived(delRequest, sender, System.currentTimeMillis()); assertEquals(0, packetFolder.getElements().size()); }
@Test public void testSign() throws MessagingException, SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, IOException, GeneralSecurityException, PasswordException { assertEquals(emails.size()-1, identities.size()); // -1 for the anonymous email that was not added to the map for (Email email: emails) { EmailIdentity identity = identities.get(email); if (identity == null) continue; // sign and verify signature email.sign(identity, TestUtil.createDummyKeyUpdateHandler()); assertTrue(email.isSignatureValid()); // write the email to a byte array, make a new email from the byte array, and verify the signature ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); KeyUpdateHandler keyUpdateHandler = TestUtil.createDummyKeyUpdateHandler(); for (UnencryptedEmailPacket packet: email.createEmailPackets(identity, keyUpdateHandler, null, I2PBotePacket.MAX_DATAGRAM_SIZE)) outputStream.write(packet.getContent()); email = new Email(outputStream.toByteArray()); assertTrue(email.isSignatureValid()); } }
/** * Decrypts the encrypted part of the packet with the private key of an <code>EmailIdentity</code>. * The {@link CryptoImplementation} in the <code>EmailIdentity</code> must be the same as the one * in this <code>EncryptedEmailPacket</code>. * @param identity * @throws GeneralSecurityException * @throws InvalidCipherTextException */ public UnencryptedEmailPacket decrypt(EmailIdentity identity) throws GeneralSecurityException { if (cryptoImpl != identity.getCryptoImpl()) throw new IllegalArgumentException("CryptoImplementations don't match. Email Packet: <" + cryptoImpl.getName() + ">, Email Identity: <" + identity.getCryptoImpl().getName() + ">."); byte[] decryptedData = cryptoImpl.decrypt(encryptedData, identity.getPublicEncryptionKey(), identity.getPrivateEncryptionKey()); return new UnencryptedEmailPacket(decryptedData); }
@Before public void setUp() throws Exception { String message = "This is a test message. Test 1 2 3 Test"; byte[] content = message.getBytes(); byte[] messageIdBytes = new byte[] {-69, -24, -109, 1, 69, -122, -69, 113, -68, -90, 55, -28, 105, 97, 125, 70, 51, 58, 14, 2, -13, -53, 90, -29, 36, 67, 36, -94, -108, -125, 11, 123}; UniqueId messageId = new UniqueId(messageIdBytes, 0); int fragmentIndex = 0; packet = new UnencryptedEmailPacket(new ByteArrayInputStream(content), messageId, fragmentIndex, I2PBotePacket.MAX_DATAGRAM_SIZE); packet.setNumFragments(1); }
@Test public void testDeleteVerificationHash() { for (int i=0; i<encryptedPackets.length; i++) { EncryptedEmailPacket packet = encryptedPackets[i]; Hash expectedHash = SHA256Generator.getInstance().calculateHash(plaintextPacket.getDeleteAuthorization().toByteArray()); assertEquals("The delete authorization key does not hash to the delete verification hash!", expectedHash, packet.getDeleteVerificationHash()); } }
@Test public void testHeaderRemoval() throws MessagingException, IOException, GeneralSecurityException, PasswordException { Email newEmail; Collection<UnencryptedEmailPacket> packets; ByteArrayOutputStream outputStream; KeyUpdateHandler keyUpdateHandler = TestUtil.createDummyKeyUpdateHandler(); // verify that all BCC addresses are removed when sending to a TO: address EmailIdentity identity2 = identities.get(bccEmail); packets = bccEmail.createEmailPackets(identity2, keyUpdateHandler, null, I2PBotePacket.MAX_DATAGRAM_SIZE); outputStream = new ByteArrayOutputStream(); for (UnencryptedEmailPacket packet: packets) outputStream.write(packet.getContent()); newEmail = new Email(outputStream.toByteArray()); assertNull("BCC headers were not removed!", newEmail.getHeader("BCC")); assertEquals(3, newEmail.getAllRecipients().length); // verify that the recipient is not removed if it is a BCC: addresses packets = bccEmail.createEmailPackets(bccIdentity, keyUpdateHandler, bccEmailDestination, I2PBotePacket.MAX_DATAGRAM_SIZE); // use the plain email dest because that is what the Email class compares against outputStream = new ByteArrayOutputStream(); for (UnencryptedEmailPacket packet: packets) outputStream.write(packet.getContent()); newEmail = new Email(outputStream.toByteArray()); assertNotNull("BCC header expected!", newEmail.getHeader("BCC")); assertEquals("One BCC header expected!", 1, newEmail.getHeader("BCC").length); assertEquals(4, newEmail.getAllRecipients().length); }