@Test public void toByteArrayAndBack() throws Exception { for (EncryptedEmailPacket packet: encryptedPackets) { byte[] arrayA = packet.toByteArray(); byte[] arrayB = new EncryptedEmailPacket(arrayA).toByteArray(); assertArrayEquals("The two arrays differ! CryptoImplementation = " + packet.getCryptoImpl().getName(), arrayA, arrayB); } }
public void put(Collection<EncryptedEmailPacket> emailPackets) { for (EncryptedEmailPacket emailPacket: emailPackets) { Hash emailPacketKey = emailPacket.getDhtKey(); Hash delVerificationHash = emailPacket.getDeleteVerificationHash(); IndexPacketEntry entry = new IndexPacketEntry(emailPacketKey, delVerificationHash); put(entry); } }
/** Overridden to set a time stamp on the packet */ @Override public void store(DhtStorablePacket packetToStore) { if (!(packetToStore instanceof EncryptedEmailPacket)) throw new IllegalArgumentException("Invalid packet type: " + packetToStore.getClass().getSimpleName() + "; this folder only stores packets of type " + EncryptedEmailPacket.class.getSimpleName() + "."); EncryptedEmailPacket emailPacket = (EncryptedEmailPacket)packetToStore; // If the packet didn't come with a time stamp, set it to the current time if (emailPacket.getStoreTime() == 0) emailPacket.setStoreTime(System.currentTimeMillis()); super.store(packetToStore); }
EmailMetadata metadata = email.getMetadata(); for (UnencryptedEmailPacket unencryptedPacket: emailPackets) { EncryptedEmailPacket emailPacket = new EncryptedEmailPacket(unencryptedPacket, recipientDest); send(emailPacket, hops, minDelay, maxDelay, relayRedundancy); indexPacket.put(emailPacket); metadata.addPacketInfo(recipientDest, emailPacket.getDhtKey(), emailPacket.getDeleteVerificationHash());
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); }
EncryptedEmailPacket emailPacket1 = new EncryptedEmailPacket(emailPkt1Data); EncryptedEmailPacket emailPacket2 = new EncryptedEmailPacket(emailPkt2Data); UniqueId delAuthKey1 = new UniqueId("nJlsaGZb1k6OFze1fUsHEF0osP5Wv9Rgta8EwHl8Te8="); // matches emailPkt1Data UniqueId delAuthKey2 = new UniqueId("ImXwDy7HZq7pyjGwxpYmlwaKAWoQlUl2fdrBK~mTt0g="); // matches emailPkt2Data String prefix1 = emailPacket1.getDhtKey().toBase64().substring(0, 2); String prefix2 = emailPacket2.getDhtKey().toBase64().substring(0, 2); assertEquals("Error setting up test packets: prefixes of DHT keys differ", prefix1, prefix2); assertFalse("Error setting up test packets: DHT keys should be different", emailPacket1.getDhtKey().equals(emailPacket2.getDhtKey())); assertEquals("Folder should have two elements!", 2, packetFolder.getElements().size()); EmailPacketDeleteRequest delRequest1 = new EmailPacketDeleteRequest(emailPacket1.getDhtKey(), delAuthKey1); packetFolder.process(delRequest1); assertEquals("Folder should have exactly one element!", 1, packetFolder.getElements().size()); EmailPacketDeleteRequest delRequest2 = new EmailPacketDeleteRequest(emailPacket2.getDhtKey(), delAuthKey2); packetFolder.process(delRequest2); assertEquals("Folder should be empty!", 0, packetFolder.getElements().size()); assertTrue(newDelRequest1 instanceof EmailPacketDeleteRequest); EmailPacketDeleteRequest newEmailPacketDelRequest1 = (EmailPacketDeleteRequest)newDelRequest1; assertEquals(newEmailPacketDelRequest1.getDhtKey(), emailPacket1.getDhtKey()); assertEquals(newEmailPacketDelRequest1.getAuthorization(), delAuthKey1); DeleteRequest newDelRequest2 = packetFolder.storeAndCreateDeleteRequest(emailPacket2); assertTrue(newDelRequest2 instanceof EmailPacketDeleteRequest); EmailPacketDeleteRequest newEmailPacketDelRequest2 = (EmailPacketDeleteRequest)newDelRequest2; assertEquals(newEmailPacketDelRequest2.getDhtKey(), emailPacket2.getDhtKey()); assertEquals(newEmailPacketDelRequest2.getAuthorization(), delAuthKey2);
/** * Returns <code>true</code> if the DHT key stored in the packet matches * the computed (from the encrypted data) DHT key. * @see #getDhtKey() */ public boolean verifyPacketHash() { return getDhtKey().equals(dhtKey); }
EncryptedEmailPacket emailPacket = (EncryptedEmailPacket)packet; if (emailPacket.verifyPacketHash()) try { UnencryptedEmailPacket decryptedPacket = emailPacket.decrypt(identity); if (validPacket == null) { emailCompleted = incompleteEmailFolder.addEmailPacket(decryptedPacket);
@Test public void testHash() throws Exception { for (EncryptedEmailPacket packet: encryptedPackets) { assertTrue("Hash not valid! CryptoImplementation = " + packet.getCryptoImpl().getName(), packet.verifyPacketHash()); alterEncryptedData(packet); assertFalse("Hash is valid, but should be invalid! CryptoImplementation = " + packet.getCryptoImpl().getName(), packet.verifyPacketHash()); } }
@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); } }
@Override public synchronized void deleteExpired() { long currentTimeMillis = System.currentTimeMillis(); for (Iterator<EncryptedEmailPacket> iterator=iterator(); iterator.hasNext();) { EncryptedEmailPacket emailPacket = iterator.next(); if (currentTimeMillis > emailPacket.getStoreTime() + EXPIRATION_TIME_MILLISECONDS) { log.debug("Deleting expired email packet: <" + emailPacket + ">"); iterator.remove(); } } }
/** * Deletes email packets. * @param delRequest An instance of {@link EmailPacketDeleteRequest} */ @Override public synchronized void process(DeleteRequest delRequest) { log.debug("Processing delete request: " + delRequest); if (!(delRequest instanceof EmailPacketDeleteRequest)) log.error("Invalid type of delete request for EmailPacketFolder: " + delRequest.getClass()); EmailPacketDeleteRequest emailPacketDelRequest = (EmailPacketDeleteRequest)delRequest; // see if the packet exists Hash dhtKey = emailPacketDelRequest.getDhtKey(); DhtStorablePacket storedPacket = retrieve(dhtKey); if (storedPacket instanceof EncryptedEmailPacket) { // verify Hash verificationHash = ((EncryptedEmailPacket)storedPacket).getDeleteVerificationHash(); UniqueId delAuthorization = emailPacketDelRequest.getAuthorization(); boolean valid = Util.isDeleteAuthorizationValid(verificationHash, delAuthorization); if (valid) delete(dhtKey, delAuthorization); else log.debug("Invalid Delete Authorization in EmailPacketDeleteRequest. Should be: <" + verificationHash.toBase64() + ">"); } else if (storedPacket != null) log.debug("EncryptedEmailPacket expected for DHT key <" + dhtKey + ">, found " + storedPacket.getClass().getSimpleName()); }
@Override public void setStoreTime(long time) { super.setStoreTime(storeTime); }
boolean equals(EncryptedEmailPacket packet1, EncryptedEmailPacket packet2) { byte[] arrayA = packet1.toByteArray(); byte[] arrayB = packet2.toByteArray(); return Arrays.equals(arrayA, arrayB); } }
/** * Creates an <code>EncryptedEmailPacket</code> from raw datagram data. * To read the encrypted parts of the packet, {@link #decrypt(EmailIdentity)} must be called first. * @param data * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException */ public EncryptedEmailPacket(byte[] data) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { super(data); ByteBuffer buffer = ByteBuffer.wrap(data, HEADER_LENGTH, data.length-HEADER_LENGTH); dhtKey = readHash(buffer); storeTime = buffer.getInt() * 1000L; delVerificationHash = readHash(buffer); byte cryptoImplId = buffer.get(); cryptoImpl = CryptoFactory.getInstance(cryptoImplId); int encryptedLength = buffer.getShort() & 0xFFFF; // length of the encrypted part of the packet encryptedData = new byte[encryptedLength]; buffer.get(encryptedData); }
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); }
EncryptedEmailPacket emailPacket3 = new EncryptedEmailPacket(unencryptedPacket2, destination1); Hash dhtKey1 = emailPacket1.getDhtKey(); Hash dhtKey3 = emailPacket3.getDhtKey(); delRequest.put(dhtKey1, unencryptedPacket1.getDeleteAuthorization()); delRequest.put(dhtKey3, unencryptedPacket2.getDeleteAuthorization());
@Test public void testSendAnonymousEmail() throws Exception { testEmail = new Email(true); testEmail.setFrom(new InternetAddress("anonymous")); testEmail.addRecipient(RecipientType.TO, new InternetAddress("Erika Mustermann <m-5~1dZ0MrGdyAWu-C2ecNAB5LCCsHQpeSfjn-r~mqMfNvroR98~BRmReUDmb0la-r-pBHLMtflrJE7aTrGwDTBm5~AJFEm-9SJPZnyGs-ed5pOj4Db65yJml1y1n77qr1~mM4GITl6KuIoxg8YwvPrCIlXe2hiiDCoC-uY9-np9UY>")); testEmail.setSubject("Test", "UTF-8"); testEmail.setText("foobar"); op.sendEmail(testEmail); ArgumentCaptor<DhtStorablePacket> arg = ArgumentCaptor.forClass(DhtStorablePacket.class); verify(dht, times(2)).store(arg.capture()); List<DhtStorablePacket> values = arg.getAllValues(); assertTrue(values.get(0) instanceof EncryptedEmailPacket); assertTrue(values.get(1) instanceof IndexPacket); assertTrue(((IndexPacket)values.get(1)).contains(((EncryptedEmailPacket)values.get(0)).getDhtKey())); } }
@Test public void testCheckExpiration() throws GeneralSecurityException, InterruptedException, PasswordException { final long cutoffTime = System.currentTimeMillis() - ExpirationListener.EXPIRATION_TIME_MILLISECONDS; // store a packet that expired 10 seconds ago long expirationTime1 = cutoffTime - 10*1000; EncryptedEmailPacket emailPacket1 = new SettableStoreTimeEncryptedEmailPacket(unencryptedPacket, recipient, expirationTime1); packetFolder.store(emailPacket1); assertEquals(expirationTime1/1000L, packetFolder.getElements().get(0).getStoreTime()/1000L); // round to seconds // store a packet that expires in 10 seconds long expirationTime2 = cutoffTime + 10*1000; EncryptedEmailPacket emailPacket2 = new SettableStoreTimeEncryptedEmailPacket(unencryptedPacket2, recipient, expirationTime2); packetFolder.store(emailPacket2); assertEquals(2, packetFolder.getElements().size()); // delete expired packets and check that one of the two packets got deleted packetFolder.deleteExpired(); assertEquals(1, packetFolder.getElements().size()); // 11 seconds later, the remaining packet should have expired TimeUnit.SECONDS.sleep(11); packetFolder.deleteExpired(); assertEquals(0, packetFolder.getElements().size()); }
@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()); } }