/** * Takes a Msg and encodes it into a single byte[], in a way that is compatible with the way that * PyBitmessage does. This payload can then be sent to a server to be disseminated across the * network. The payload is stored as a Payload object. * * @param encMsg - A msg Object containing the message data used to create the payload. * @param powDone - A boolean value indicating whether or not POW has been done for this message * @param toPubkey - A Pubkey object containing the data for the Pubkey of the address that this * message is being sent to * @return A Payload object containing the message payload */ private Payload constructMsgPayloadForDissemination( BMObject encMsg, boolean powDone, Pubkey toPubkey) { // Create a new Payload object to hold the payload data Payload msgPayload = new Payload(); msgPayload.setBelongsToMe(true); msgPayload.setPOWDone(powDone); msgPayload.setType(Payload.OBJECT_TYPE_MSG); // Encode the POW nonce, expiration time, object type, object version, and stream number values // into byte form byte[] powNonceBytes = ByteUtils.longToBytes(encMsg.getPOWNonce()); byte[] expirationTimeBytes = ByteUtils.longToBytes(encMsg.getExpirationTime()); byte[] objectTypeBytes = ByteUtils.intToBytes(OBJECT_TYPE_MSG); byte[] objectVersionBytes = VarintEncoder.encode(OBJECT_VERSION_MSG); byte[] streamNumberBytes = VarintEncoder.encode(encMsg.getStreamNumber()); byte[] payload = null; ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try { if (powDone) { outputStream.write(powNonceBytes); } outputStream.write(expirationTimeBytes); outputStream.write(objectTypeBytes); outputStream.write(objectVersionBytes); outputStream.write(streamNumberBytes); outputStream.write(encMsg.getPayload()); payload = outputStream.toByteArray(); outputStream.close(); } catch (IOException e) { throw new RuntimeException( "IOException occurred in DataProcessor.constructMsgPayloadForDissemination()", e); } msgPayload.setPayload(payload); // Save the Payload object to the database PayloadProvider payProv = PayloadProvider.get(App.getContext()); long msgPayloadId = payProv.addPayload(msgPayload); // Finally, set the msg payload ID to the one generated by the SQLite database msgPayload.setId(msgPayloadId); return msgPayload; }
/** * Takes an UnencryptedMsg object and does all the work necessary to transform it into an * EncyrptedMsg object that is ready to be serialised and sent out to the Bitmessage network. The * two major parts of this process are encryption and proof of work. <br> * <br> * <b>NOTE!</b> Calling this method results in proof of work calculations being done for the * message. This can take a long time and lots of CPU power!<br> * <br> * * @param message - The original plain text Message object, provided so that its status can be * updated during the process * @param unencMsg - The UnencryptedMsg object to be encrypted * @param toPubkey - The Pubkey object containing the public encryption key of the intended * message recipient * @param doPOW - A boolean value indicating whether or not POW should be done for this message * @param timeToLive - The 'time to live' value (in seconds) to be used in creating this msg * @return A Msg object containing the encrypted message data */ private BMObject constructMsg( Message message, UnencryptedMsg unencMsg, Pubkey toPubkey, boolean doPOW, long timeToLive) { // Reconstruct the ECPublicKey object from the byte[] found the the relevant PubKey ECPublicKey publicEncryptionKey = new KeyConverter().reconstructPublicKey(toPubkey.getPublicEncryptionKey()); // Construct the payload to be encrypted byte[] msgDataForEncryption = constructMsgPayloadForEncryption(unencMsg); // Update the status of this message displayed in the UI String messageStatus = App.getContext().getString(R.string.message_status_encrypting_message); MessageStatusHandler.updateMessageStatus(message, messageStatus); // Encrypt the payload CryptProcessor cryptProc = new CryptProcessor(); byte[] encryptedPayload = cryptProc.encrypt(msgDataForEncryption, publicEncryptionKey); // Create a new Msg object and populate its fields BMObject msg = new BMObject(); msg.setBelongsToMe( true); // NOTE: This method assumes that any message I am encrypting 'belongs to me' (i.e. // The user of the application is the author of the message) msg.setExpirationTime(unencMsg.getExpirationTime()); msg.setObjectType(unencMsg.getObjectType()); msg.setObjectVersion(unencMsg.getObjectVersion()); msg.setStreamNumber(toPubkey.getStreamNumber()); msg.setPayload(encryptedPayload); if (doPOW) { MessageStatusHandler.updateMessageStatus( message, App.getContext().getString(R.string.message_status_doing_pow)); // Do proof of work for the Msg object Log.i(TAG, "About to do POW calculations for a msg that we are sending"); byte[] powPayload = constructMsgPayloadForPOW(msg); long powNonce = new POWProcessor() .doPOW( powPayload, unencMsg.getExpirationTime(), toPubkey.getNonceTrialsPerByte(), toPubkey.getExtraBytes()); msg.setPOWNonce(powNonce); } else { msg.setPOWNonce( (long) 0); // If POW is not to be done for this message, set the powNonce as zero for now. } return msg; }
/** * Takes a Msg and constructs the payload needed to do POW for it. * * @param msg - The msg Object to construct the POW payload for * @return The POW payload */ private byte[] constructMsgPayloadForPOW(BMObject msg) { try { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); outputStream.write( ByteUtils.longToBytes( msg.getExpirationTime())); // This conversion results in a byte[] of length 8, which // is what we want outputStream.write(ByteUtils.intToBytes(OBJECT_TYPE_MSG)); outputStream.write(VarintEncoder.encode(OBJECT_VERSION_MSG)); outputStream.write(VarintEncoder.encode(msg.getStreamNumber())); outputStream.write(msg.getPayload()); return outputStream.toByteArray(); } catch (IOException e) { throw new RuntimeException( "IOException occurred in OutgoingMessageProcessor.constructMsgPayloadForPOW()", e); } }