From 1eb685179801cccfac64ff6006b85f74ab5ed4df Mon Sep 17 00:00:00 2001
From: Christian Basler
* You'll need the Builder to create a BitmessageContext, and set the following properties:
*
*
* The default implementations in the different module builds can be used.
- *
+ *
* The port defaults to 8444 (the default Bitmessage port) + *
*/ public class BitmessageContext { public static final int CURRENT_VERSION = 3; diff --git a/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java b/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java index 600ee4f..e7f56f5 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/InternalContext.java @@ -35,8 +35,9 @@ import static ch.dissem.bitmessage.utils.UnixTime.DAY; * The internal context should normally only be used for port implementations. If you need it in your client * implementation, you're either doing something wrong, something very weird, or the BitmessageContext should * get extended. - * + ** On the other hand, if you need the BitmessageContext in a port implementation, the same thing might apply. + *
*/ public class InternalContext { private final static Logger LOG = LoggerFactory.getLogger(InternalContext.class); diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java b/domain/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java index 923f101..eb348a2 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java @@ -158,7 +158,7 @@ public class BitmessageAddress { } /** - * Returns the private key used to decrypt Pubkey objects (for v4 addresses) and broadcasts. + * @return the private key used to decrypt Pubkey objects (for v4 addresses) and broadcasts. */ public byte[] getPublicDecryptionKey() { return publicDecryptionKey; diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java index 8fe6ff8..5fc3990 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java @@ -47,11 +47,11 @@ public class CryptoBox implements Streamable { private final byte[] mac; private byte[] encrypted; - public CryptoBox(Streamable data, byte[] encryptionKey) { + public CryptoBox(Streamable data, byte[] encryptionKey) throws IOException { this(data, Security.keyToPoint(encryptionKey)); } - public CryptoBox(Streamable data, ECPoint K) { + public CryptoBox(Streamable data, ECPoint K) throws IOException { curveType = 0x02CA; // 1. The destination public key is called K. @@ -71,7 +71,7 @@ public class CryptoBox implements Streamable { byte[] key_m = Arrays.copyOfRange(H, 32, 64); // 7. Pad the input text to a multiple of 16 bytes, in accordance to PKCS7. // 8. Encrypt the data with AES-256-CBC, using IV as initialization vector, key_e as encryption key and the padded input text as payload. Call the output cipher text. - encrypted = crypt(true, Bytes.from(data), key_e); + encrypted = crypt(true, Encode.bytes(data), key_e); // 9. Calculate a 32 byte MAC with HMACSHA256, using key_m as salt and IV + R + cipher text as data. Call the output MAC. mac = calculateMac(key_m); @@ -99,6 +99,9 @@ public class CryptoBox implements Streamable { } /** + * @param privateKey a private key, typically should be 32 bytes long + * @return an InputStream yielding the decrypted data + * @throws DecryptionFailedException if the payload can't be decrypted using this private key * @see https://bitmessage.org/wiki/Encryption#Decryption */ public InputStream decrypt(byte[] privateKey) throws DecryptionFailedException { diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java index e23ab11..e31dbe3 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/GetPubkey.java @@ -50,7 +50,7 @@ public class GetPubkey extends ObjectPayload { } /** - * Returns an array of bytes that represent either the ripe, or the tag of an address, depending on the + * @return an array of bytes that represent either the ripe, or the tag of an address, depending on the * address version. */ public byte[] getRipeTag() { diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectPayload.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectPayload.java index 39c28ff..ef42718 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectPayload.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/ObjectPayload.java @@ -50,7 +50,7 @@ public abstract class ObjectPayload implements Streamable { } /** - * The ECDSA signature which, as of protocol v3, covers the object header starting with the time, + * @return the ECDSA signature which, as of protocol v3, covers the object header starting with the time, * appended with the data described in this table down to the extra_bytes. Therefore, this must * be checked and set in the {@link ObjectMessage} object. */ diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java b/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java index b77220b..e1bd8f2 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java @@ -31,12 +31,15 @@ public class Label { } /** - * RGBA representation for the color. + * @return RGBA representation for the color. */ public int getColor() { return color; } + /** + * @param color RGBA representation for the color. + */ public void setColor(int color) { this.color = color; } @@ -50,14 +53,14 @@ public class Label { return id; } - public Type getType() { - return type; - } - public void setId(Object id) { this.id = id; } + public Type getType() { + return type; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/AddressRepository.java b/domain/src/main/java/ch/dissem/bitmessage/ports/AddressRepository.java index 7cd6be8..2770997 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ports/AddressRepository.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/AddressRepository.java @@ -26,7 +26,7 @@ public interface AddressRepository { BitmessageAddress findIdentity(byte[] ripeOrTag); /** - * Returns all Bitmessage addresses that belong to this user, i.e. have a private key. + * @return all Bitmessage addresses that belong to this user, i.e. have a private key. */ List+ * Please note that a new {@link MessageDigest} object is created at each call (to ensure thread safety), so you + * shouldn't use this if you need to do many hash calculations in short order on the same thread. + *
+ * + * @param data to get hashed + * @param length number of bytes to be taken into account + * @return SHA-512 hash of data + */ public static byte[] doubleSha512(byte[] data, int length) { MessageDigest mda = md("SHA-512"); mda.update(data, 0, length); return mda.digest(mda.digest()); } + + /** + * A helper method to calculate RIPEMD-160 hashes. Supplying multiple byte arrays has the same result as a + * concatenation of all arrays, but might perform better. + *+ * Please note that a new {@link MessageDigest} object is created at + * each call (to ensure thread safety), so you shouldn't use this if you need to do many hash calculations in short + * order on the same thread. + *
+ * + * @param data to get hashed + * @return RIPEMD-160 hash of data + */ public static byte[] ripemd160(byte[]... data) { return hash("RIPEMD160", data); } + /** + * A helper method to calculate double SHA-256 hashes. This method allows to only use a part of the available bytes + * to use for the hash calculation. + *+ * Please note that a new {@link MessageDigest} object is created at + * each call (to ensure thread safety), so you shouldn't use this if you need to do many hash calculations in short + * order on the same thread. + *
+ * + * @param data to get hashed + * @param length number of bytes to be taken into account + * @return SHA-256 hash of data + */ public static byte[] doubleSha256(byte[] data, int length) { MessageDigest mda = md("SHA-256"); mda.update(data, 0, length); return mda.digest(mda.digest()); } + /** + * A helper method to calculate SHA-1 hashes. Supplying multiple byte arrays has the same result as a + * concatenation of all arrays, but might perform better. + *+ * Please note that a new {@link MessageDigest} object is created at + * each call (to ensure thread safety), so you shouldn't use this if you need to do many hash calculations in short + * order on the same thread. + *
+ * + * @param data to get hashed + * @return SHA hash of data + */ public static byte[] sha1(byte[]... data) { return hash("SHA-1", data); } + /** + * @param length number of bytes to return + * @return an array of the given size containing random bytes + */ public static byte[] randomBytes(int length) { byte[] result = new byte[length]; RANDOM.nextBytes(result); return result; } - public static void doProofOfWork(ObjectMessage object, ProofOfWorkEngine worker, long nonceTrialsPerByte, long extraBytes) { + /** + * Calculates the proof of work. This might take a long time, depending on the hardware, message size and time to + * live. + * + * @param object to do the proof of work for + * @param worker doing the actual proof of work + * @param nonceTrialsPerByte difficulty + * @param extraBytes bytes to add to the object size (makes it more difficult to send small messages) + */ + public static void doProofOfWork(ObjectMessage object, ProofOfWorkEngine worker, long nonceTrialsPerByte, + long extraBytes) { try { if (nonceTrialsPerByte < 1000) nonceTrialsPerByte = 1000; if (extraBytes < 1000) extraBytes = 1000; @@ -107,9 +188,13 @@ public class Security { } /** - * @throws InsufficientProofOfWorkException if proof of work doesn't check out + * @param object to be checked + * @param nonceTrialsPerByte difficulty + * @param extraBytes bytes to add to the object size + * @throws InsufficientProofOfWorkException if proof of work doesn't check out (makes it more difficult to send small messages) */ - public static void checkProofOfWork(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) throws IOException { + public static void checkProofOfWork(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) + throws IOException { byte[] target = getProofOfWorkTarget(object, nonceTrialsPerByte, extraBytes); byte[] value = Security.doubleSha512(object.getNonce(), getInitialHash(object)); if (Bytes.lt(target, value, 8)) { @@ -146,6 +231,13 @@ public class Security { } } + /** + * Calculates the MAC for a message (data) + * + * @param key_m the symmetric key used + * @param data the message data to calculate the MAC for + * @return the MAC + */ public static byte[] mac(byte[] key_m, byte[] data) { try { Mac mac = Mac.getInstance("HmacSHA256", "BC"); @@ -156,6 +248,18 @@ public class Security { } } + /** + * Create a new public key fom given private keys. + * + * @param version of the public key / address + * @param stream of the address + * @param privateSigningKey private key used for signing + * @param privateEncryptionKey private key used for encryption + * @param nonceTrialsPerByte proof of work difficulty + * @param extraBytes bytes to add for the proof of work (make it harder for small messages) + * @param features of the address + * @return a public key object + */ public static Pubkey createPubkey(long version, long stream, byte[] privateSigningKey, byte[] privateEncryptionKey, long nonceTrialsPerByte, long extraBytes, Pubkey.Feature... features) { return Factory.createPubkey(version, stream, @@ -164,10 +268,18 @@ public class Security { nonceTrialsPerByte, extraBytes, features); } + /** + * @param privateKey private key as byte array + * @return a public key corresponding to the given private key + */ public static ECPoint createPublicKey(byte[] privateKey) { return EC_CURVE_PARAMETERS.getG().multiply(keyToBigInt(privateKey)).normalize(); } + /** + * @param privateKey private key as byte array + * @return a big integer representation (unsigned) of the given bytes + */ public static BigInteger keyToBigInt(byte[] privateKey) { return new BigInteger(1, privateKey); } @@ -185,7 +297,13 @@ public class Security { ); } - public static boolean isSignatureValid(byte[] bytesToSign, byte[] signature, Pubkey pubkey) { + /** + * @param data to check + * @param signature the signature of the message + * @param pubkey the sender's public key + * @return true if the signature is valid, false otherwise + */ + public static boolean isSignatureValid(byte[] data, byte[] signature, Pubkey pubkey) { try { ECParameterSpec spec = new ECParameterSpec( EC_CURVE_PARAMETERS.getCurve(), @@ -201,13 +319,20 @@ public class Security { Signature sig = Signature.getInstance("ECDSA", "BC"); sig.initVerify(publicKey); - sig.update(bytesToSign); + sig.update(data); return sig.verify(signature); } catch (Exception e) { throw new RuntimeException(e); } } + /** + * Calculate the signature of data, using the given private key. + * + * @param data to be signed + * @param privateKey to be used for signing + * @return the signature + */ public static byte[] getSignature(byte[] data, ch.dissem.bitmessage.entity.valueobject.PrivateKey privateKey) { try { ECParameterSpec spec = new ECParameterSpec( @@ -231,6 +356,9 @@ public class Security { } } + /** + * @return a random number of type long + */ public static long randomNonce() { return RANDOM.nextLong(); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/UnixTime.java b/domain/src/main/java/ch/dissem/bitmessage/utils/UnixTime.java index f5d8052..ffd4df8 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/utils/UnixTime.java +++ b/domain/src/main/java/ch/dissem/bitmessage/utils/UnixTime.java @@ -30,7 +30,7 @@ public class UnixTime { public static final long DAY = 24 * HOUR; /** - * Returns the time in second based Unix time ({@link System#currentTimeMillis()}/1000) + * @return the time in second based Unix time ({@link System#currentTimeMillis()}/1000) */ public static long now() { return System.currentTimeMillis() / 1000; @@ -38,6 +38,9 @@ public class UnixTime { /** * Same as {@link #now()} + shiftSeconds, but might be more readable. + * + * @param shiftSeconds number of seconds from now we're interested in + * @return the Unix time in shiftSeconds seconds / shiftSeconds seconds ago */ public static long now(long shiftSeconds) { return (System.currentTimeMillis() / 1000) + shiftSeconds;