diff --git a/build.xml b/build.xml index c58311eb7..634b27de3 100644 --- a/build.xml +++ b/build.xml @@ -91,7 +91,7 @@ - + diff --git a/pom.xml b/pom.xml index 298d521d5..a1b463032 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ net.sourceforge.plantuml plantuml - 1.2021.5-SNAPSHOT + 1.2021.6-SNAPSHOT jar PlantUML @@ -94,21 +94,6 @@ 1.0.7 test - - org.eclipse.elk - org.eclipse.elk.core - 0.7.1 - - - org.eclipse.elk - org.eclipse.elk.alg.layered - 0.7.1 - - - org.eclipse.elk - org.eclipse.elk.alg.mrtree - 0.7.1 - diff --git a/skin/plantuml.skin b/skin/plantuml.skin index ae4a21a2b..55b28739f 100644 --- a/skin/plantuml.skin +++ b/skin/plantuml.skin @@ -290,6 +290,10 @@ ganttDiagram { timeline { BackgroundColor transparent } + closed { + BackGroundColor #E0E8E8 + FontColor #909898 + } task { RoundCorner 0 Margin 2 2 2 2 diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/Argon2.java b/src/ext/plantuml/com/at/gadermaier/argon2/Argon2.java new file mode 100644 index 000000000..b4110ed28 --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/Argon2.java @@ -0,0 +1,271 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2; + +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Defaults.LANES_DEF; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Defaults.LOG_M_COST_DEF; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Defaults.OUTLEN_DEF; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Defaults.TYPE_DEF; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Defaults.T_COST_DEF; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Defaults.VERSION_DEF; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.util.Arrays; + +import ext.plantuml.com.at.gadermaier.argon2.algorithm.FillMemory; +import ext.plantuml.com.at.gadermaier.argon2.algorithm.Finalize; +import ext.plantuml.com.at.gadermaier.argon2.algorithm.Initialize; +import ext.plantuml.com.at.gadermaier.argon2.model.Argon2Type; +import ext.plantuml.com.at.gadermaier.argon2.model.Instance; + +public class Argon2 { + + private byte[] output; + private int outputLength; // -l N + private double duration; + + private byte[] password; + private byte[] salt; + private byte[] secret; + private byte[] additional; + + private int iterations; // -t N + private int memory; // -m N + private int lanes; // -p N + + private int version; // -v (10/13) + private Argon2Type type; + + private boolean clearMemory = true; + private Charset charset = Charset.forName("UTF-8"); + + private boolean encodedOnly = false; + private boolean rawOnly = false; + + Argon2() { + this.lanes = LANES_DEF; + this.outputLength = OUTLEN_DEF; + this.memory = 1 << LOG_M_COST_DEF; + this.iterations = T_COST_DEF; + this.version = VERSION_DEF; + this.type = TYPE_DEF; + } + + private static byte[] toByteArray(char[] chars, Charset charset) { + assert chars != null; + + CharBuffer charBuffer = CharBuffer.wrap(chars); + ByteBuffer byteBuffer = charset.encode(charBuffer); + byte[] bytes = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit()); + Arrays.fill(byteBuffer.array(), (byte) 0); + return bytes; + } + + public void hashNow() { + try { + Validation.validateInput(this); + + long start = System.nanoTime(); + + Instance instance = new Instance(this); + + Initialize.initialize(instance, this); + FillMemory.fillMemoryBlocks(instance); + Finalize.finalize(instance, this); + + duration = (System.nanoTime() - start) / 1000000000.0; + } finally { + clear(); + } + } + + public void clear() { + if (password != null) + Arrays.fill(password, 0, password.length - 1, (byte) 0); + + if (salt != null) + Arrays.fill(salt, 0, salt.length - 1, (byte) 0); + + if (secret != null) + Arrays.fill(secret, 0, secret.length - 1, (byte) 0); + + if (additional != null) + Arrays.fill(additional, 0, additional.length - 1, (byte) 0); + } + + void printSummary() { + if (encodedOnly) + System.out.println(getEncoded()); + else if (rawOnly) + System.out.println(getOutputString()); + else { + System.out.println("Type:\t\t" + type); + System.out.println("Iterations:\t" + iterations); + System.out.println("Memory:\t\t" + memory + " KiB"); + System.out.println("Parallelism:\t" + lanes); + System.out.println("Hash:\t\t" + getOutputString()); + System.out.println("Encoded:\t " + getEncoded()); + System.out.println(duration + " seconds"); + } + } + + public Argon2 setMemoryInKiB(int memory) { + this.memory = memory; + return this; + } + + public Argon2 setParallelism(int parallelism) { + this.lanes = parallelism; + return this; + } + + public Argon2 setPassword(char[] password) { + return setPassword(toByteArray(password, charset)); + } + + public Argon2 setSalt(String salt) { + return setSalt(salt.getBytes(charset)); + } + + public byte[] getOutput() { + return output; + } + + public void setOutput(byte[] finalResult) { + this.output = finalResult; + } + + public String getOutputString() { + return Util.bytesToHexString(output); + } + + public int getOutputLength() { + return outputLength; + } + + public Argon2 setOutputLength(int outputLength) { + this.outputLength = outputLength; + return this; + } + + public byte[] getPassword() { + return password; + } + + public Argon2 setPassword(byte[] password) { + this.password = password; + return this; + } + + public int getPasswordLength() { + return password.length; + } + + public byte[] getSalt() { + return salt; + } + + public Argon2 setSalt(byte[] salt) { + this.salt = salt; + return this; + } + + public int getSaltLength() { + return salt.length; + } + + public byte[] getSecret() { + return secret; + } + + public Argon2 setSecret(byte[] secret) { + this.secret = secret; + return this; + } + + public int getSecretLength() { + return secret != null ? secret.length : 0; + } + + public byte[] getAdditional() { + return additional; + } + + public Argon2 setAdditional(byte[] additional) { + this.additional = additional; + return this; + } + + public int getAdditionalLength() { + return additional != null ? additional.length : 0; + } + + public int getIterations() { + return iterations; + } + + public Argon2 setIterations(int iterations) { + this.iterations = iterations; + return this; + } + + public int getMemory() { + return memory; + } + + public Argon2 setMemory(int memory) { + this.memory = 1 << memory; + return this; + } + + public int getLanes() { + return lanes; + } + + public int getVersion() { + return version; + } + + public Argon2 setVersion(int version) { + this.version = version; + return this; + } + + public Argon2Type getType() { + return type; + } + + public Argon2 setType(Argon2Type type) { + this.type = type; + return this; + } + + public boolean isClearMemory() { + return clearMemory; + } + + public void setClearMemory(boolean clearMemory) { + this.clearMemory = clearMemory; + } + + public Charset getCharset() { + return charset; + } + + public void setEncodedOnly(boolean encodedOnly) { + this.encodedOnly = encodedOnly; + } + + public void setRawOnly(boolean rawOnly) { + this.rawOnly = rawOnly; + } + + public String getEncoded() { + return ""; // TODO + } +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/Argon2Factory.java b/src/ext/plantuml/com/at/gadermaier/argon2/Argon2Factory.java new file mode 100644 index 000000000..35ee5aa84 --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/Argon2Factory.java @@ -0,0 +1,12 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2; + +public class Argon2Factory { + public static Argon2 create(){ + return new Argon2(); + } +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/Constants.java b/src/ext/plantuml/com/at/gadermaier/argon2/Constants.java new file mode 100644 index 000000000..55feec121 --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/Constants.java @@ -0,0 +1,102 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2; + +import ext.plantuml.com.at.gadermaier.argon2.model.Argon2Type; + +public class Constants { + + /* Memory block size in bytes */ + public static final int ARGON2_BLOCK_SIZE = 1024; + public static final int ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8; + /* Number of pseudo-random values generated by one call to Blake in Argon2i + to + generate reference block positions + */ + public static final int ARGON2_ADDRESSES_IN_BLOCK = 128; + /* Pre-hashing digest length and its extension*/ + public static final int ARGON2_PREHASH_DIGEST_LENGTH = 64; + public static final int ARGON2_PREHASH_SEED_LENGTH = 72; + /* Number of synchronization points between lanes per pass */ + public static final int ARGON2_SYNC_POINTS = 4; + /* Flags to determine which fields are securely wiped (default = no wipe). */ + public static final int ARGON2_DEFAULT_FLAGS = 0; + public static final int ARGON2_VERSION_10 = 0x10; + public static final int ARGON2_VERSION_13 = 0x13; + + public static class Defaults { + + public static final int OUTLEN_DEF = 32; + public static final int T_COST_DEF = 3; + public static final int LOG_M_COST_DEF = 12; + public static final int LANES_DEF = 1; + public static final Argon2Type TYPE_DEF = Argon2Type.Argon2i; + public static final int VERSION_DEF = ARGON2_VERSION_13; + public static final int ARGON2_VERSION_NUMBER = ARGON2_VERSION_13; + public static final boolean ENCODED_ONLY = false; + public static final boolean RAW_ONLY = false; + } + //public static int ARGON2_FLAG_CLEAR_PASSWORD (UINT32_C(1) << 0) + //public static int ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1) + + /* + * Argon2 input parameter restrictions + */ + public static class Constraints { + + public static final int MAX_PASSWORD_LEN = 128; + + /* Minimum and maximum number of lanes (degree of parallelism) */ + public static final int MIN_PARALLELISM = 1; + public static final int MAX_PARALLELISM = 16777216; + + /* Minimum and maximum digest size in bytes */ + public static final int MIN_OUTLEN = 4; + public static final int MAX_OUTLEN = Integer.MAX_VALUE; + + /* Minimum and maximum number of memory blocks (each of BLOCK_SIZE bytes) */ + public static final int MIN_MEMORY = (2 * ARGON2_SYNC_POINTS); /* 2 blocks per slice */ + + /* Minimum and maximum number of passes */ + public static final int MIN_ITERATIONS = 1; + public static final int MAX_ITERATIONS = Integer.MAX_VALUE; + + /* Minimum and maximum password length in bytes */ + public static final int MIN_PWD_LENGTH = 0; + public static final int MAX_PWD_LENGTH = Integer.MAX_VALUE; + + /* Minimum and maximum salt length in bytes */ + public static final int MIN_SALT_LENGTH = 0; + public static final int MAX_SALT_LENGTH = Integer.MAX_VALUE; + + /* Minimum and maximum key length in bytes */ + public static final int MAX_SECRET_LENGTH = Integer.MAX_VALUE; + + /* Minimum and maximum associated model length in bytes */ + public static final int MAX_AD_LENGTH = Integer.MAX_VALUE; + } + + public static class Messages { + public static final String P_MIN_MSG = "degree of parallelism cannot be smaller than one"; + public static final String P_MAX_MSG = "parallelism cannot be greater than 16777216"; + + public static final String M_MIN_MSG = "memory too small"; + + public static final String T_MIN_MSG = "number of iterations cannot be less than one"; + public static final String T_MAX_MSG = "number of iterations too high"; + + public static final String PWD_MIN_MSG = "password too short"; + public static final String PWD_MAX_MSG = "password too long"; + + public static final String SALT_MIN_MSG = "salt too short"; + public static final String SALT_MAX_MSG = "salt too long"; + + public static final String SECRET_MAX_MSG = "secret too long"; + public static final String ADDITIONAL_MAX_MSG = "additional data too long"; + + } + +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/Util.java b/src/ext/plantuml/com/at/gadermaier/argon2/Util.java new file mode 100644 index 000000000..257c0338c --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/Util.java @@ -0,0 +1,67 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2; + +public class Util { + + public static String bytesToHexString(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02x", b & 0xff)); + } + return sb.toString(); + } + + public static byte[] hexStringToByteArray(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i+1), 16)); + } + return data; + } + + public static long littleEndianBytesToLong(byte[] b) { + long result = 0; + for (int i = 7; i >= 0; i--) { + result <<= 8; + result |= (b[i] & 0xFF); + } + return result; + } + + public static byte[] intToLittleEndianBytes(int a) { + byte[] result = new byte[4]; + result[0] = (byte) (a & 0xFF); + result[1] = (byte) ((a >> 8) & 0xFF); + result[2] = (byte) ((a >> 16) & 0xFF); + result[3] = (byte) ((a >> 24) & 0xFF); + return result; + } + + public static byte[] longToLittleEndianBytes(long a) { + byte[] result = new byte[8]; + result[0] = (byte) (a & 0xFF); + result[1] = (byte) ((a >> 8) & 0xFF); + result[2] = (byte) ((a >> 16) & 0xFF); + result[3] = (byte) ((a >> 24) & 0xFF); + result[4] = (byte) ((a >> 32) & 0xFF); + result[5] = (byte) ((a >> 40) & 0xFF); + result[6] = (byte) ((a >> 48) & 0xFF); + result[7] = (byte) ((a >> 56) & 0xFF); + return result; + } + + public static long intToLong(int x){ + byte[] intBytes = intToLittleEndianBytes(x); + byte[] bytes = new byte[8]; + System.arraycopy(intBytes, 0, bytes, 0, 4); + return littleEndianBytesToLong(bytes); + } + +} + diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/Validation.java b/src/ext/plantuml/com/at/gadermaier/argon2/Validation.java new file mode 100644 index 000000000..199bf2415 --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/Validation.java @@ -0,0 +1,63 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2; + +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Constraints.MAX_AD_LENGTH; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Constraints.MAX_ITERATIONS; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Constraints.MAX_PARALLELISM; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Constraints.MAX_PWD_LENGTH; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Constraints.MAX_SALT_LENGTH; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Constraints.MAX_SECRET_LENGTH; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Constraints.MIN_ITERATIONS; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Constraints.MIN_PARALLELISM; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Constraints.MIN_PWD_LENGTH; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Constraints.MIN_SALT_LENGTH; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Messages.ADDITIONAL_MAX_MSG; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Messages.M_MIN_MSG; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Messages.PWD_MAX_MSG; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Messages.PWD_MIN_MSG; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Messages.P_MAX_MSG; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Messages.P_MIN_MSG; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Messages.SALT_MAX_MSG; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Messages.SALT_MIN_MSG; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Messages.SECRET_MAX_MSG; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Messages.T_MAX_MSG; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.Messages.T_MIN_MSG; + +import ext.plantuml.com.at.gadermaier.argon2.exception.Argon2InvalidParameterException; + +class Validation { + + static void validateInput(Argon2 argon2){ + String message = null; + + if (argon2.getLanes() < MIN_PARALLELISM) + message = P_MIN_MSG; + else if (argon2.getLanes() > MAX_PARALLELISM) + message = P_MAX_MSG; + else if(argon2.getMemory() < 2 * argon2.getLanes()) + message = M_MIN_MSG; + else if(argon2.getIterations() < MIN_ITERATIONS) + message = T_MIN_MSG; + else if(argon2.getIterations() > MAX_ITERATIONS) + message = T_MAX_MSG; + else if(argon2.getPasswordLength() < MIN_PWD_LENGTH) + message = PWD_MIN_MSG; + else if(argon2.getPasswordLength() > MAX_PWD_LENGTH) + message = PWD_MAX_MSG; + else if(argon2.getSaltLength() < MIN_SALT_LENGTH) + message = SALT_MIN_MSG; + else if(argon2.getSaltLength() > MAX_SALT_LENGTH) + message = SALT_MAX_MSG; + else if(argon2.getSecretLength() > MAX_SECRET_LENGTH) + message = SECRET_MAX_MSG; + else if(argon2.getAdditionalLength() > MAX_AD_LENGTH) + message = ADDITIONAL_MAX_MSG; + + if(message != null) + throw new Argon2InvalidParameterException(message); + } +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/FillBlock.java b/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/FillBlock.java new file mode 100644 index 000000000..a3024a9f0 --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/FillBlock.java @@ -0,0 +1,55 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2.algorithm; + +import ext.plantuml.com.at.gadermaier.argon2.model.Block; + +class FillBlock { + + static void fillBlock(Block X, Block Y, Block currentBlock, boolean withXor) { + + Block R = new Block(); + Block Z = new Block(); + + R.xor(X, Y); + Z.copyBlock(R); + + /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then + (16,17,..31)... finally (112,113,...127) */ + for (int i = 0; i < 8; i++) { + + Functions.roundFunction(Z, + 16 * i, 16 * i + 1, 16 * i + 2, + 16 * i + 3, 16 * i + 4, 16 * i + 5, + 16 * i + 6, 16 * i + 7, 16 * i + 8, + 16 * i + 9, 16 * i + 10, 16 * i + 11, + 16 * i + 12, 16 * i + 13, 16 * i + 14, + 16 * i + 15 + ); + } + + /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then + (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ + for (int i = 0; i < 8; i++) { + + Functions.roundFunction(Z, + 2 * i, 2 * i + 1, 2 * i + 16, + 2 * i + 17, 2 * i + 32, 2 * i + 33, + 2 * i + 48, 2 * i + 49, 2 * i + 64, + 2 * i + 65, 2 * i + 80, 2 * i + 81, + 2 * i + 96, 2 * i + 97, 2 * i + 112, + 2 * i + 113 + ); + + } + + if (withXor) { + currentBlock.xor(R, Z, currentBlock); + } else { + currentBlock.xor(R, Z); + } + } +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/FillMemory.java b/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/FillMemory.java new file mode 100644 index 000000000..21f92095c --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/FillMemory.java @@ -0,0 +1,80 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2.algorithm; + +import static ext.plantuml.com.at.gadermaier.argon2.Constants.ARGON2_SYNC_POINTS; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import ext.plantuml.com.at.gadermaier.argon2.model.Instance; +import ext.plantuml.com.at.gadermaier.argon2.model.Position; + +public class FillMemory { + + public static void fillMemoryBlocks(Instance instance) { + if (instance.getLanes() == 1) { + fillMemoryBlockSingleThreaded(instance); + } else { + fillMemoryBlockMultiThreaded(instance); + } + } + + private static void fillMemoryBlockSingleThreaded(Instance instance) { + for (int i = 0; i < instance.getIterations(); i++) { + for (int j = 0; j < ARGON2_SYNC_POINTS; j++) { + Position position = new Position(i, 0, j, 0); + FillSegment.fillSegment(instance, position); + } + } + } + + private static void fillMemoryBlockMultiThreaded(final Instance instance) { + + ExecutorService service = Executors.newFixedThreadPool(instance.getLanes()); + List> futures = new ArrayList>(); + + for (int i = 0; i < instance.getIterations(); i++) { + for (int j = 0; j < ARGON2_SYNC_POINTS; j++) { + for (int k = 0; k < instance.getLanes(); k++) { + + final Position position = new Position(i, k, j, 0); + + Future future = service.submit(new Runnable() { + @Override + public void run() { + FillSegment.fillSegment(instance, position); + } + }); + + futures.add(future); + } + + joinThreads(instance, futures); + } + } + + service.shutdownNow(); + } + + private static void joinThreads(Instance instance, List> futures) { + try { + for (Future f : futures) { + f.get(); + } + } catch (InterruptedException e) { + instance.clear(); + throw new RuntimeException(e); + } catch (ExecutionException e) { + instance.clear(); + throw new RuntimeException(e); + } + } +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/FillSegment.java b/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/FillSegment.java new file mode 100644 index 000000000..c11485526 --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/FillSegment.java @@ -0,0 +1,170 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2.algorithm; + +import static ext.plantuml.com.at.gadermaier.argon2.Constants.ARGON2_ADDRESSES_IN_BLOCK; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.ARGON2_VERSION_10; + +import ext.plantuml.com.at.gadermaier.argon2.Constants; +import ext.plantuml.com.at.gadermaier.argon2.Util; +import ext.plantuml.com.at.gadermaier.argon2.model.Argon2Type; +import ext.plantuml.com.at.gadermaier.argon2.model.Block; +import ext.plantuml.com.at.gadermaier.argon2.model.Instance; +import ext.plantuml.com.at.gadermaier.argon2.model.Position; + + +class FillSegment { + + static void fillSegment(Instance instance, Position position) { + + Block addressBlock = null, inputBlock = null, zeroBlock = null; + + boolean dataIndependentAddressing = isDataIndependentAddressing(instance, position); + int startingIndex = getStartingIndex(position); + int currentOffset = position.lane * instance.getLaneLength() + position.slice * instance.getSegmentLength() + startingIndex; + int prevOffset = getPrevOffset(instance, currentOffset); + + if (dataIndependentAddressing) { + addressBlock = new Block(); + zeroBlock = new Block(); + inputBlock = new Block(); + + initAddressBlocks(instance, position, zeroBlock, inputBlock, addressBlock); + } + + for (position.index = startingIndex; position.index < instance.getSegmentLength(); position.index++, currentOffset++, prevOffset++) { + prevOffset = rotatePrevOffset(instance, currentOffset, prevOffset); + + long pseudoRandom = getPseudoRandom(instance, position, addressBlock, inputBlock, zeroBlock, prevOffset, dataIndependentAddressing); + int refLane = getRefLane(instance, position, pseudoRandom); + int refColumn = getRefColumn(instance, position, pseudoRandom, refLane == position.lane); + + /* 2 Creating a new block */ + Block prevBlock = instance.memory[prevOffset]; + Block refBlock = instance.memory[((instance.getLaneLength()) * refLane + refColumn)]; + Block currentBlock = instance.memory[currentOffset]; + + boolean withXor = isWithXor(instance, position); + FillBlock.fillBlock(prevBlock, refBlock, currentBlock, withXor); + } + } + + private static boolean isDataIndependentAddressing(Instance instance, Position position) { + return (instance.getType() == Argon2Type.Argon2i) || + (instance.getType() == Argon2Type.Argon2id + && (position.pass == 0) + && (position.slice < Constants.ARGON2_SYNC_POINTS / 2) + ); + } + + private static void initAddressBlocks(Instance instance, Position position, Block zeroBlock, Block inputBlock, Block addressBlock) { + inputBlock.v[0] = Util.intToLong(position.pass); + inputBlock.v[1] = Util.intToLong(position.lane); + inputBlock.v[2] = Util.intToLong(position.slice); + inputBlock.v[3] = Util.intToLong(instance.memory.length); + inputBlock.v[4] = Util.intToLong(instance.getIterations()); + inputBlock.v[5] = Util.intToLong(instance.getType().ordinal()); + + if ((position.pass == 0) && (position.slice == 0)) { + /* Don't forget to generate the first block of addresses: */ + nextAddresses(zeroBlock, inputBlock, addressBlock); + } + } + + private static boolean isWithXor(Instance instance, Position position) { + return !(position.pass == 0 || instance.getVersion() == ARGON2_VERSION_10); + } + + private static int getPrevOffset(Instance instance, int currentOffset) { + if (currentOffset % instance.getLaneLength() == 0) { + /* Last block in this lane */ + return currentOffset + instance.getLaneLength() - 1; + } else { + /* Previous block */ + return currentOffset - 1; + } + } + + private static int rotatePrevOffset(Instance instance, int currentOffset, int prevOffset) { + if (currentOffset % instance.getLaneLength() == 1) { + prevOffset = currentOffset - 1; + } + return prevOffset; + } + + private static int getStartingIndex(Position position) { + if ((position.pass == 0) && (position.slice == 0)) { + return 2; /* we have already generated the first two blocks */ + } else { + return 0; + } + } + + private static void nextAddresses(Block zeroBlock, Block inputBlock, Block addressBlock) { + inputBlock.v[6]++; + FillBlock.fillBlock(zeroBlock, inputBlock, addressBlock, false); + FillBlock.fillBlock(zeroBlock, addressBlock, addressBlock, false); + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + private static long getPseudoRandom(Instance instance, Position position, Block addressBlock, Block inputBlock, Block zeroBlock, int prevOffset, boolean dataIndependentAddressing) { + if (dataIndependentAddressing) { + if (position.index % ARGON2_ADDRESSES_IN_BLOCK == 0) { + nextAddresses(zeroBlock, inputBlock, addressBlock); + } + return addressBlock.v[position.index % ARGON2_ADDRESSES_IN_BLOCK]; + } else { + return instance.memory[prevOffset].v[0]; + } + } + + private static int getRefLane(Instance instance, Position position, long pseudoRandom) { + int refLane = (int) (((pseudoRandom >>> 32)) % instance.getLanes()); + + if ((position.pass == 0) && (position.slice == 0)) { + /* Can not reference other lanes yet */ + refLane = position.lane; + } + return refLane; + } + + private static int getRefColumn(Instance instance, Position position, long pseudoRandom, + boolean sameLane) { + + int referenceAreaSize; + int startPosition; + + if (position.pass == 0) { + startPosition = 0; + + if (sameLane) { + /* The same lane => add current segment */ + referenceAreaSize = position.slice * instance.getSegmentLength() + position.index - 1; + } else { + /* pass == 0 && !sameLane => position.slice > 0*/ + referenceAreaSize = position.slice * instance.getSegmentLength() + ((position.index == 0) ? (-1) : 0); + } + + } else { + startPosition = ((position.slice + 1) * instance.getSegmentLength()) % instance.getLaneLength(); + + if (sameLane) { + referenceAreaSize = instance.getLaneLength() - instance.getSegmentLength() + position.index - 1; + } else { + referenceAreaSize = instance.getLaneLength() - instance.getSegmentLength() + ((position.index == 0) ? (-1) : 0); + } + } + + long relativePosition = pseudoRandom & 0xFFFFFFFFL; +// long relativePosition = pseudoRandom << 32 >>> 32; + relativePosition = (relativePosition * relativePosition) >>> 32; + relativePosition = referenceAreaSize - 1 - (referenceAreaSize * relativePosition >>> 32); + + return (int) (startPosition + relativePosition) % instance.getLaneLength(); + } + +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/Finalize.java b/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/Finalize.java new file mode 100644 index 000000000..af8e6b8a7 --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/Finalize.java @@ -0,0 +1,34 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2.algorithm; + +import ext.plantuml.com.at.gadermaier.argon2.Argon2; +import ext.plantuml.com.at.gadermaier.argon2.model.Block; +import ext.plantuml.com.at.gadermaier.argon2.model.Instance; + +public class Finalize { + + public static void finalize(Instance instance, Argon2 argon2) { + + Block finalBlock = instance.memory[instance.getLaneLength() - 1]; + + /* XOR the last blocks */ + for (int i = 1; i < instance.getLanes(); i++) { + int lastBlockInLane = i * instance.getLaneLength() + (instance.getLaneLength() - 1); + finalBlock.xorWith(instance.memory[lastBlockInLane]); + } + + byte[] finalBlockBytes = finalBlock.toBytes(); + byte[] finalResult = Functions.blake2bLong(finalBlockBytes, argon2.getOutputLength()); + + argon2.setOutput(finalResult); + + if (argon2.isClearMemory()) { + instance.clear(); + argon2.clear(); + } + } +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/Functions.java b/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/Functions.java new file mode 100644 index 000000000..5b407982a --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/Functions.java @@ -0,0 +1,172 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2.algorithm; + +import static ext.plantuml.com.at.gadermaier.argon2.Constants.ARGON2_BLOCK_SIZE; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.ARGON2_PREHASH_DIGEST_LENGTH; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.ARGON2_PREHASH_SEED_LENGTH; + +import ext.plantuml.com.at.gadermaier.argon2.Util; +import ext.plantuml.com.at.gadermaier.argon2.blake2.Blake2b; +import ext.plantuml.com.at.gadermaier.argon2.model.Block; + +class Functions { + + + /** + * H0 = H64(p, τ, m, t, v, y, |P|, P, |S|, S, |L|, K, |X|, X) + * -> 64 byte (ARGON2_PREHASH_DIGEST_LENGTH) + */ + static byte[] initialHash(byte[] lanes, byte[] outputLength, + byte[] memory, byte[] iterations, + byte[] version, byte[] type, + byte[] passwordLength, byte[] password, + byte[] saltLength, byte[] salt, + byte[] secretLength, byte[] secret, + byte[] additionalLength, byte[] additional) { + + + Blake2b.Param params = new Blake2b.Param() + .setDigestLength(ARGON2_PREHASH_DIGEST_LENGTH); + + final Blake2b blake2b = Blake2b.Digest.newInstance(params); + + blake2b.update(lanes); + blake2b.update(outputLength); + blake2b.update(memory); + blake2b.update(iterations); + blake2b.update(version); + blake2b.update(type); + + blake2b.update(passwordLength); + if (password != null) { + blake2b.update(password); + } + + blake2b.update(saltLength); + if (salt != null) { + blake2b.update(salt); + } + + blake2b.update(secretLength); + if (secret != null) { + blake2b.update(secret); + } + + blake2b.update(additionalLength); + if (additional != null) { + blake2b.update(additional); + } + + byte[] blake2hash = blake2b.digest(); + assert (blake2hash.length == 64); + + return blake2hash; + } + + + /** + * H' - blake2bLong - variable length hash function + */ + static byte[] blake2bLong(byte[] input, int outputLength) { + + assert (input.length == ARGON2_PREHASH_SEED_LENGTH || input.length == ARGON2_BLOCK_SIZE); + + byte[] result = new byte[outputLength]; + byte[] outlenBytes = Util.intToLittleEndianBytes(outputLength); + + int blake2bLength = 64; + + if (outputLength <= blake2bLength) { + result = blake2b(input, outlenBytes, outputLength); + } else { + byte[] outBuffer; + + /* V1 */ + outBuffer = blake2b(input, outlenBytes, blake2bLength); + System.arraycopy(outBuffer, 0, result, 0, blake2bLength / 2); + + int r = (outputLength / 32) + (outputLength % 32 == 0 ? 0 : 1) - 2; + + int position = blake2bLength / 2; + for (int i = 2; i <= r; i++, position += blake2bLength / 2) { + /* V2 to Vr */ + outBuffer = blake2b(outBuffer, null, blake2bLength); + System.arraycopy(outBuffer, 0, result, position, blake2bLength / 2); + } + + int lastLength = outputLength - 32 * r; + + /* Vr+1 */ + outBuffer = blake2b(outBuffer, null, lastLength); + System.arraycopy(outBuffer, 0, result, position, lastLength); + } + + assert (result.length == outputLength); + return result; + } + + private static byte[] blake2b(byte[] input, byte[] outlenBytes, int outputLength) { + Blake2b.Param params = new Blake2b.Param() + .setDigestLength(outputLength); + + final Blake2b blake2b = Blake2b.Digest.newInstance(params); + + if (outlenBytes != null) + blake2b.update(outlenBytes); + + blake2b.update(input); + + return blake2b.digest(); + } + + static void roundFunction(Block block, + int v0, int v1, int v2, int v3, + int v4, int v5, int v6, int v7, + int v8, int v9, int v10, int v11, + int v12, int v13, int v14, int v15) { + + F(block, v0, v4, v8, v12); + F(block, v1, v5, v9, v13); + F(block, v2, v6, v10, v14); + F(block, v3, v7, v11, v15); + + F(block, v0, v5, v10, v15); + F(block, v1, v6, v11, v12); + F(block, v2, v7, v8, v13); + F(block, v3, v4, v9, v14); + } + + private static void F(Block block, int a, int b, int c, int d) { + fBlaMka(block, a, b); + rotr64(block, d, a, 32); + + fBlaMka(block, c, d); + rotr64(block, b, c, 24); + + fBlaMka(block, a, b); + rotr64(block, d, a, 16); + + fBlaMka(block, c, d); + rotr64(block, b, c, 63); + } + + /*designed by the Lyra PHC team */ + /* a <- a + b + 2*aL*bL + * + == addition modulo 2^64 + * aL = least 32 bit */ + private static void fBlaMka(Block block, int x, int y) { + final long m = 0xFFFFFFFFL; + final long xy = (block.v[x] & m) * (block.v[y] & m); + + block.v[x] = block.v[x] + block.v[y] + 2 * xy; + } + + private static void rotr64(Block block, int v, int w, long c) { + final long temp = block.v[v] ^ block.v[w]; + block.v[v] = (temp >>> c) | (temp << (64 - c)); + } +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/Initialize.java b/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/Initialize.java new file mode 100644 index 000000000..e7940ccce --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/algorithm/Initialize.java @@ -0,0 +1,75 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2.algorithm; + +import static ext.plantuml.com.at.gadermaier.argon2.Constants.ARGON2_BLOCK_SIZE; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.ARGON2_PREHASH_DIGEST_LENGTH; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.ARGON2_PREHASH_SEED_LENGTH; + +import ext.plantuml.com.at.gadermaier.argon2.Argon2; +import ext.plantuml.com.at.gadermaier.argon2.Util; +import ext.plantuml.com.at.gadermaier.argon2.model.Instance; + +public class Initialize { + + + public static void initialize(Instance instance, Argon2 argon2) { + byte[] initialHash = Functions.initialHash( + Util.intToLittleEndianBytes(argon2.getLanes()), + Util.intToLittleEndianBytes(argon2.getOutputLength()), + Util.intToLittleEndianBytes(argon2.getMemory()), + Util.intToLittleEndianBytes(argon2.getIterations()), + Util.intToLittleEndianBytes(argon2.getVersion()), + Util.intToLittleEndianBytes(argon2.getType().ordinal()), + Util.intToLittleEndianBytes(argon2.getPasswordLength()), + argon2.getPassword(), + Util.intToLittleEndianBytes(argon2.getSaltLength()), + argon2.getSalt(), + Util.intToLittleEndianBytes(argon2.getSecretLength()), + argon2.getSecret(), + Util.intToLittleEndianBytes(argon2.getAdditionalLength()), + argon2.getAdditional() + ); + fillFirstBlocks(instance, initialHash); + } + + /** + * (H0 || 0 || i) 72 byte -> 1024 byte + * (H0 || 1 || i) 72 byte -> 1024 byte + */ + private static void fillFirstBlocks(Instance instance, byte[] initialHash) { + + final byte[] zeroBytes = {0, 0, 0, 0}; + final byte[] oneBytes = {1, 0, 0, 0}; + + byte[] initialHashWithZeros = getInitialHashLong(initialHash, zeroBytes); + byte[] initialHashWithOnes = getInitialHashLong(initialHash, oneBytes); + + for (int i = 0; i < instance.getLanes(); i++) { + + byte[] iBytes = Util.intToLittleEndianBytes(i); + + System.arraycopy(iBytes, 0, initialHashWithZeros, ARGON2_PREHASH_DIGEST_LENGTH + 4, 4); + System.arraycopy(iBytes, 0, initialHashWithOnes, ARGON2_PREHASH_DIGEST_LENGTH + 4, 4); + + byte[] blockhashBytes = Functions.blake2bLong(initialHashWithZeros, ARGON2_BLOCK_SIZE); + instance.memory[i * instance.getLaneLength() + 0].fromBytes(blockhashBytes); + + blockhashBytes = Functions.blake2bLong(initialHashWithOnes, ARGON2_BLOCK_SIZE); + instance.memory[i * instance.getLaneLength() + 1].fromBytes(blockhashBytes); + } + } + + private static byte[] getInitialHashLong(byte[] initialHash, byte[] appendix) { + byte[] initialHashLong = new byte[ARGON2_PREHASH_SEED_LENGTH]; + + System.arraycopy(initialHash, 0, initialHashLong, 0, ARGON2_PREHASH_DIGEST_LENGTH); + System.arraycopy(appendix, 0, initialHashLong, ARGON2_PREHASH_DIGEST_LENGTH, 4); + + return initialHashLong; + } + +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/blake2/Blake2b.java b/src/ext/plantuml/com/at/gadermaier/argon2/blake2/Blake2b.java new file mode 100644 index 000000000..5a42e8ac8 --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/blake2/Blake2b.java @@ -0,0 +1,1288 @@ + + +/* This file is taken from + https://github.com/alphazero/Blake2b/ + + Original Author: Andreas Gadermaier + because the repository artifact was not uploaded to maven central repository + + */ +/* + A Java implementation of BLAKE2B cryptographic digest algorithm. + + Joubin Mohammad Houshyar + bushwick, nyc + 02-14-2014 + + -- + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ + +package ext.plantuml.com.at.gadermaier.argon2.blake2; + + +import static ext.plantuml.com.at.gadermaier.argon2.blake2.Blake2b.Engine.Assert.*; +import static ext.plantuml.com.at.gadermaier.argon2.blake2.Blake2b.Engine.LittleEndian.*; + +import java.io.PrintStream; +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; + + +/** */ +public interface Blake2b { + /** */ + void update(byte[] input); + + // --------------------------------------------------------------------- + // API + // --------------------------------------------------------------------- + // TODO add ByteBuffer variants + + /** */ + void update(byte input); + + /** */ + void update(byte[] input, int offset, int len); + + /** */ + byte[] digest(); + + /** */ + byte[] digest(byte[] input); + + /** */ + void digest(byte[] output, int offset, int len); + + /** */ + void reset(); + + // --------------------------------------------------------------------- + // Specification + // --------------------------------------------------------------------- + public interface Spec { + /** pblock size of blake2b */ + int param_bytes = 64; + + /** pblock size of blake2b */ + int block_bytes = 128; + + /** maximum digest size */ + int max_digest_bytes = 64; + + /** maximum key sie */ + int max_key_bytes = 64; + + /** maximum salt size */ + int max_salt_bytes = 16; + + /** maximum personalization string size */ + int max_personalization_bytes = 16; + + /** length of h space vector array */ + int state_space_len = 8; + + /** max tree fanout value */ + int max_tree_fantout = 0xFF; + + /** max tree depth value */ + int max_tree_depth = 0xFF; + + /** max tree leaf length value.Note that this has uint32 semantics + and thus 0xFFFFFFFF is used as max value limit. */ + int max_tree_leaf_length = 0xFFFFFFFF; + + /** max node offset value. Note that this has uint64 semantics + and thus 0xFFFFFFFFFFFFFFFFL is used as max value limit. */ + long max_node_offset = 0xFFFFFFFFFFFFFFFFL; + + /** max tree inner length value */ + int max_tree_inner_length = 0xFF; + + /** initialization values map ref-Spec IV[i] -> slice iv[i*8:i*8+7] */ + long[] IV = { + 0x6a09e667f3bcc908L, + 0xbb67ae8584caa73bL, + 0x3c6ef372fe94f82bL, + 0xa54ff53a5f1d36f1L, + 0x510e527fade682d1L, + 0x9b05688c2b3e6c1fL, + 0x1f83d9abfb41bd6bL, + 0x5be0cd19137e2179L + }; + + /** sigma per spec used in compress func generation - for reference only */ + static byte[][] sigma = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } + }; + } + + // --------------------------------------------------------------------- + // Blake2b Message Digest + // --------------------------------------------------------------------- + + /** Generalized Blake2b digest. */ + public static class Digest extends Engine implements Blake2b { + private Digest (final Param p) { super (p); } + private Digest () { super (); } + + public static Digest newInstance () { + return new Digest (); + } + public static Digest newInstance (final int digestLength) { + return new Digest (new Param().setDigestLength(digestLength)); + } + public static Digest newInstance (Param p) { + return new Digest (p); + } + } + + // --------------------------------------------------------------------- + // Blake2b Message Authentication Code + // --------------------------------------------------------------------- + + /** Message Authentication Code (MAC) digest. */ + public static class Mac extends Engine implements Blake2b { + private Mac (final Param p) { super (p); } + private Mac () { super (); } + + /** Blake2b.MAC 512 - using default Blake2b.Spec settings with given key */ + public static Mac newInstance (final byte[] key) { + return new Mac (new Param().setKey(key)); + } + /** Blake2b.MAC - using default Blake2b.Spec settings with given key, with given digest length */ + public static Mac newInstance (final byte[] key, final int digestLength) { + return new Mac (new Param().setKey(key).setDigestLength(digestLength)); + } + /** Blake2b.MAC - using default Blake2b.Spec settings with given java.security.Key, with given digest length */ + public static Mac newInstance (final Key key, final int digestLength) { + return new Mac (new Param().setKey(key).setDigestLength(digestLength)); + } + /** Blake2b.MAC - using the specified Parameters. + * @param p asserted valid configured Param with key */ + public static Mac newInstance (Param p) { + assert p != null : "Param (p) is null"; + assert p.hasKey() : "Param (p) not configured with a key"; + return new Mac (p); + } + } + + // --------------------------------------------------------------------- + // Blake2b Incremental Message Digest (Tree) + // --------------------------------------------------------------------- + + /** + * Note that Tree is just a convenience class; incremental hash (tree) + * can be done directly with the Digest class. + *
+ * Further node, that tree does NOT accumulate the leaf hashes -- + * you need to do that + */ + public static class Tree { + + final int depth; + final int fanout; + final int leaf_length; + final int inner_length; + final int digest_length; + + /** + * + * @param fanout + * @param depth + * @param leaf_length size of data input for leaf nodes. + * @param inner_length note this is used also as digest-length for non-root nodes. + * @param digest_length final hash out digest-length for the tree + */ + public Tree ( + final int depth, + final int fanout, + final int leaf_length, + final int inner_length, + final int digest_length + ) { + this.fanout = fanout; + this.depth = depth; + this.leaf_length = leaf_length; + this.inner_length = inner_length; + this.digest_length = digest_length; + } + private Param treeParam() { + return new Param(). + setDepth(depth).setFanout(fanout).setLeafLength(leaf_length).setInnerLength(inner_length); + } + /** returns the Digest for tree node @ (depth, offset) */ + public final Digest getNode (final int depth, final int offset) { + final Param nodeParam = treeParam().setNodeDepth(depth).setNodeOffset(offset).setDigestLength(inner_length); + return Digest.newInstance(nodeParam); + } + /** returns the Digest for root node */ + public final Digest getRoot () { + final int depth = this.depth - 1; + final Param rootParam = treeParam().setNodeDepth(depth).setNodeOffset(0L).setDigestLength(digest_length); + return Digest.newInstance(rootParam); + } + } + + // --------------------------------------------------------------------- + // Engine + // --------------------------------------------------------------------- + static class Engine implements Blake2b { + + /* G0 sigmas */ + static final int[] sig_g00 = { 0, 14, 11, 7, 9, 2, 12, 13, 6, 10, 0, 14, }; + static final int[] sig_g01 = { 1, 10, 8, 9, 0, 12, 5, 11, 15, 2, 1, 10, }; + + /* G1 sigmas */ + static final int[] sig_g10 = { 2, 4, 12, 3, 5, 6, 1, 7, 14, 8, 2, 4, }; + static final int[] sig_g11 = { 3, 8, 0, 1, 7, 10, 15, 14, 9, 4, 3, 8, }; + + /* G2 sigmas */ + static final int[] sig_g20 = { 4, 9, 5, 13, 2, 0, 14, 12, 11, 7, 4, 9, }; + static final int[] sig_g21 = { 5, 15, 2, 12, 4, 11, 13, 1, 3, 6, 5, 15, }; + + /* G3 sigmas */ + static final int[] sig_g30 = { 6, 13, 15, 11, 10, 8, 4, 3, 0, 1, 6, 13, }; + static final int[] sig_g31 = { 7, 6, 13, 14, 15, 3, 10, 9, 8, 5, 7, 6, }; + + /* G4 sigmas */ + static final int[] sig_g40 = { 8, 1, 10, 2, 14, 4, 0, 5, 12, 15, 8, 1, }; + static final int[] sig_g41 = { 9, 12, 14, 6, 1, 13, 7, 0, 2, 11, 9, 12, }; + + /* G5 sigmas */ + static final int[] sig_g50 = { 10, 0, 3, 5, 11, 7, 6, 15, 13, 9, 10, 0, }; + static final int[] sig_g51 = { 11, 2, 6, 10, 12, 5, 3, 4, 7, 14, 11, 2, }; + + /* G6 sigmas */ + static final int[] sig_g60 = { 12, 11, 7, 4, 6, 15, 9, 8, 1, 3, 12, 11, }; + static final int[] sig_g61 = { 13, 7, 1, 0, 8, 14, 2, 6, 4, 12, 13, 7, }; + + /* G7 sigmas */ + static final int[] sig_g70 = { 14, 5, 9, 15, 3, 1, 8, 2, 10, 13, 14, 5, }; + static final int[] sig_g71 = { 15, 3, 4, 8, 13, 9, 11, 10, 5, 0, 15, 3, }; + + // --------------------------------------------------------------------- + // Blake2b State(+) per reference implementation + // --------------------------------------------------------------------- + // REVU: address last_node TODO part of the Tree/incremental + /** + * read only + */ + private static byte[] zeropad = new byte[Spec.block_bytes]; + /** + * per spec + */ + private final long[] h = new long [ 8 ]; + /** per spec */ + private final long[] t = new long [ 2 ]; + /** per spec */ + private final long[] f = new long [ 2 ]; + /** pulled up 2b optimal */ + private final long[] m = new long [16]; + /** pulled up 2b optimal */ + private final long[] v = new long [16]; + + /** compressor cache buffer */ + private final byte[] buffer; + /** configuration params */ + private final Param param; + /** digest length from init param - copied here on init */ + private final int outlen; + /** + * per spec (tree) + */ + private boolean last_node = false; + /** + * compressor cache buffer offset/cached data length + */ + private int buflen; + /** to support update(byte) */ + private byte[] oneByte; + + /** Basic use constructor pending (TODO) JCA/JCE compliance */ + Engine() { + this(new Param()); + } + + // --------------------------------------------------------------------- + // Ctor & Initialization + // --------------------------------------------------------------------- + + /** User provided Param for custom configurations */ + Engine(final Param param) { + assert param != null : "param is null"; + this.param = param; + this.buffer = new byte[Spec.block_bytes]; + this.oneByte = new byte[1]; + this.outlen = param.getDigestLength(); + + if (param.getDepth() > Param.Default.depth) { + final int ndepth = param.getNodeDepth(); + final long nxoff = param.getNodeOffset(); + if (ndepth == param.getDepth() - 1) { + last_node = true; + assert param.getNodeOffset() == 0 : "root must have offset of zero"; + } else if (param.getNodeOffset() == param.getFanout() - 1) { + this.last_node = true; + } + } + + initialize(); + +// Debug.dumpBuffer(System.out, "param bytes at init", param.getBytes()); + + } + + public static void main(String... args) { + Blake2b mac = Blake2b.Mac.newInstance("LOVE".getBytes()); + final byte[] hash = mac.digest("Salaam!".getBytes()); +// Debug.dumpBuffer(System.out, "-- mac hash --", hash); + } + + private void initialize () { + // state vector h - copy values to address reset() requests + System.arraycopy( param.initialized_H(), 0, this.h, 0, Spec.state_space_len); + +// Debug.dumpArray("init H", this.h); + // if we have a key update initial block + // Note param has zero padded key_bytes to Spec.max_key_bytes + if(param.hasKey){ + this.update (param.key_bytes, 0, Spec.block_bytes); + } + } + + /** + * {@inheritDoc} + */ + @Override + final public void reset() { + // reset cache + this.buflen = 0; + for (int i = 0; i < buffer.length; i++) { + buffer[i] = (byte) 0; + } + + // reset flags + this.f[0] = 0L; + this.f[1] = 0L; + + // reset counters + this.t[0] = 0L; + this.t[1] = 0L; + + // reset state vector + // NOTE: keep as last stmt as init calls update0 for MACs. + initialize(); + } + + // --------------------------------------------------------------------- + // interface: Blake2b API + // --------------------------------------------------------------------- + + /** {@inheritDoc} */ + @Override final public void update (final byte[] b, int off, int len) { + if (b == null) { + throw new IllegalArgumentException("input buffer (b) is null"); + } + /* zero or more calls to compress */ + // REVU: possibly the double buffering of c-ref is more sensible .. + // regardless, the hotspot is in the compress, as expected. + while (len > 0) { + if ( buflen == 0) { + /* try compressing direct from input ? */ + while ( len > Spec.block_bytes ) { + this.t[0] += Spec.block_bytes; + this.t[1] += this.t[0] == 0 ? 1 : 0; + compress( b, off); + len -= Spec.block_bytes; + off += Spec.block_bytes; + } + } else if ( buflen == Spec.block_bytes ) { + /* flush */ + this.t[0] += Spec.block_bytes; + this.t[1] += this.t[0] == 0 ? 1 : 0; + compress( buffer, 0 ); + buflen = 0; + continue; + } + + // "are we there yet?" + if( len == 0 ) return; + + final int cap = Spec.block_bytes - buflen; + final int fill = len > cap ? cap : len; + System.arraycopy( b, off, buffer, buflen, fill ); + buflen += fill; + len -= fill; + off += fill; + } + } + + /** {@inheritDoc} */ + @Override final public void update (byte b) { + oneByte[0] = b; + update (oneByte, 0, 1); + } + + /** {@inheritDoc} */ + @Override final public void update(byte[] input) { + update (input, 0, input.length); + } + + /** {@inheritDoc} */ + @Override final public void digest(byte[] output, int off, int len) { + // zero pad last block; set last block flags; and compress + System.arraycopy( zeropad, 0, buffer, buflen, Spec.block_bytes - buflen); + if(buflen > 0) { + this.t[0] += buflen; + this.t[1] += this.t[0] == 0 ? 1 : 0; + } + + this.f[ flag.last_block ] = 0xFFFFFFFFFFFFFFFFL; + this.f[ flag.last_node ] = this.last_node ? 0xFFFFFFFFFFFFFFFFL : 0x0L; + + // compres and write final out (truncated to len) to output + compress( buffer, 0 ); + hashout( output, off, len ); + + reset(); + } + + /** {@inheritDoc} */ + @Override final public byte[] digest () throws IllegalArgumentException { + final byte[] out = new byte [outlen]; + digest ( out, 0, outlen ); + return out; + } + + /** {@inheritDoc} */ + @Override final public byte[] digest (byte[] input) { + update(input, 0, input.length); + return digest(); + } + + /** + * write out the digest output from the 'h' registers. + * truncate full output if necessary. + */ + private void hashout (final byte[] out, final int offset, final int hashlen) { + // write max number of whole longs + final int lcnt = hashlen >>> 3; + long v = 0; + int i = offset; + for (int w = 0; w < lcnt; w++) { + v = h [ w ]; + out [ i++ ] = (byte) v; v >>>= 8; + out [ i++ ] = (byte) v; v >>>= 8; + out [ i++ ] = (byte) v; v >>>= 8; + out [ i++ ] = (byte) v; v >>>= 8; + out [ i++ ] = (byte) v; v >>>= 8; + out [ i++ ] = (byte) v; v >>>= 8; + out [ i++ ] = (byte) v; v >>>= 8; + out [ i++ ] = (byte) v; + } + + // basta? + if( hashlen == Spec.max_digest_bytes) return; + + // write the remaining bytes of a partial long value + v = h[lcnt]; + i = lcnt << 3; + while (i < hashlen) { + out[offset + i] = (byte) v; + v >>>= 8; + ++i; + } + } + + // --------------------------------------------------------------------- + // Internal Ops + // --------------------------------------------------------------------- + + /** compress Spec.block_bytes data from b, from offset */ + private void compress(final byte[] b, final int offset) { + + // set m registers + // REVU: some small gains still possible here. + m[0] = ((long) b[offset] & 0xFF); + m[0] |= ((long) b[offset + 1] & 0xFF) << 8; + m[0] |= ((long) b[offset + 2] & 0xFF) << 16; + m[0] |= ((long) b[offset + 3] & 0xFF) << 24; + m[0] |= ((long) b[offset + 4] & 0xFF) << 32; + m[0] |= ((long) b[offset + 5] & 0xFF) << 40; + m[0] |= ((long) b[offset + 6] & 0xFF) << 48; + m[0] |= ((long) b[offset + 7]) << 56; + + m[1] = ((long) b[offset + 8] & 0xFF); + m[1] |= ((long) b[offset + 9] & 0xFF) << 8; + m[1] |= ((long) b[offset + 10] & 0xFF) << 16; + m[1] |= ((long) b[offset + 11] & 0xFF) << 24; + m[1] |= ((long) b[offset + 12] & 0xFF) << 32; + m[1] |= ((long) b[offset + 13] & 0xFF) << 40; + m[1] |= ((long) b[offset + 14] & 0xFF) << 48; + m[1] |= ((long) b[offset + 15]) << 56; + + m[2] = ((long) b[offset + 16] & 0xFF); + m[2] |= ((long) b[offset + 17] & 0xFF) << 8; + m[2] |= ((long) b[offset + 18] & 0xFF) << 16; + m[2] |= ((long) b[offset + 19] & 0xFF) << 24; + m[2] |= ((long) b[offset + 20] & 0xFF) << 32; + m[2] |= ((long) b[offset + 21] & 0xFF) << 40; + m[2] |= ((long) b[offset + 22] & 0xFF) << 48; + m[2] |= ((long) b[offset + 23]) << 56; + + m[3] = ((long) b[offset + 24] & 0xFF); + m[3] |= ((long) b[offset + 25] & 0xFF) << 8; + m[3] |= ((long) b[offset + 26] & 0xFF) << 16; + m[3] |= ((long) b[offset + 27] & 0xFF) << 24; + m[3] |= ((long) b[offset + 28] & 0xFF) << 32; + m[3] |= ((long) b[offset + 29] & 0xFF) << 40; + m[3] |= ((long) b[offset + 30] & 0xFF) << 48; + m[3] |= ((long) b[offset + 31]) << 56; + + m[4] = ((long) b[offset + 32] & 0xFF); + m[4] |= ((long) b[offset + 33] & 0xFF) << 8; + m[4] |= ((long) b[offset + 34] & 0xFF) << 16; + m[4] |= ((long) b[offset + 35] & 0xFF) << 24; + m[4] |= ((long) b[offset + 36] & 0xFF) << 32; + m[4] |= ((long) b[offset + 37] & 0xFF) << 40; + m[4] |= ((long) b[offset + 38] & 0xFF) << 48; + m[4] |= ((long) b[offset + 39]) << 56; + + m[5] = ((long) b[offset + 40] & 0xFF); + m[5] |= ((long) b[offset + 41] & 0xFF) << 8; + m[5] |= ((long) b[offset + 42] & 0xFF) << 16; + m[5] |= ((long) b[offset + 43] & 0xFF) << 24; + m[5] |= ((long) b[offset + 44] & 0xFF) << 32; + m[5] |= ((long) b[offset + 45] & 0xFF) << 40; + m[5] |= ((long) b[offset + 46] & 0xFF) << 48; + m[5] |= ((long) b[offset + 47]) << 56; + + m[6] = ((long) b[offset + 48] & 0xFF); + m[6] |= ((long) b[offset + 49] & 0xFF) << 8; + m[6] |= ((long) b[offset + 50] & 0xFF) << 16; + m[6] |= ((long) b[offset + 51] & 0xFF) << 24; + m[6] |= ((long) b[offset + 52] & 0xFF) << 32; + m[6] |= ((long) b[offset + 53] & 0xFF) << 40; + m[6] |= ((long) b[offset + 54] & 0xFF) << 48; + m[6] |= ((long) b[offset + 55]) << 56; + + m[7] = ((long) b[offset + 56] & 0xFF); + m[7] |= ((long) b[offset + 57] & 0xFF) << 8; + m[7] |= ((long) b[offset + 58] & 0xFF) << 16; + m[7] |= ((long) b[offset + 59] & 0xFF) << 24; + m[7] |= ((long) b[offset + 60] & 0xFF) << 32; + m[7] |= ((long) b[offset + 61] & 0xFF) << 40; + m[7] |= ((long) b[offset + 62] & 0xFF) << 48; + m[7] |= ((long) b[offset + 63]) << 56; + + m[8] = ((long) b[offset + 64] & 0xFF); + m[8] |= ((long) b[offset + 65] & 0xFF) << 8; + m[8] |= ((long) b[offset + 66] & 0xFF) << 16; + m[8] |= ((long) b[offset + 67] & 0xFF) << 24; + m[8] |= ((long) b[offset + 68] & 0xFF) << 32; + m[8] |= ((long) b[offset + 69] & 0xFF) << 40; + m[8] |= ((long) b[offset + 70] & 0xFF) << 48; + m[8] |= ((long) b[offset + 71]) << 56; + + m[9] = ((long) b[offset + 72] & 0xFF); + m[9] |= ((long) b[offset + 73] & 0xFF) << 8; + m[9] |= ((long) b[offset + 74] & 0xFF) << 16; + m[9] |= ((long) b[offset + 75] & 0xFF) << 24; + m[9] |= ((long) b[offset + 76] & 0xFF) << 32; + m[9] |= ((long) b[offset + 77] & 0xFF) << 40; + m[9] |= ((long) b[offset + 78] & 0xFF) << 48; + m[9] |= ((long) b[offset + 79]) << 56; + + m[10] = ((long) b[offset + 80] & 0xFF); + m[10] |= ((long) b[offset + 81] & 0xFF) << 8; + m[10] |= ((long) b[offset + 82] & 0xFF) << 16; + m[10] |= ((long) b[offset + 83] & 0xFF) << 24; + m[10] |= ((long) b[offset + 84] & 0xFF) << 32; + m[10] |= ((long) b[offset + 85] & 0xFF) << 40; + m[10] |= ((long) b[offset + 86] & 0xFF) << 48; + m[10] |= ((long) b[offset + 87]) << 56; + + m[11] = ((long) b[offset + 88] & 0xFF); + m[11] |= ((long) b[offset + 89] & 0xFF) << 8; + m[11] |= ((long) b[offset + 90] & 0xFF) << 16; + m[11] |= ((long) b[offset + 91] & 0xFF) << 24; + m[11] |= ((long) b[offset + 92] & 0xFF) << 32; + m[11] |= ((long) b[offset + 93] & 0xFF) << 40; + m[11] |= ((long) b[offset + 94] & 0xFF) << 48; + m[11] |= ((long) b[offset + 95]) << 56; + + m[12] = ((long) b[offset + 96] & 0xFF); + m[12] |= ((long) b[offset + 97] & 0xFF) << 8; + m[12] |= ((long) b[offset + 98] & 0xFF) << 16; + m[12] |= ((long) b[offset + 99] & 0xFF) << 24; + m[12] |= ((long) b[offset + 100] & 0xFF) << 32; + m[12] |= ((long) b[offset + 101] & 0xFF) << 40; + m[12] |= ((long) b[offset + 102] & 0xFF) << 48; + m[12] |= ((long) b[offset + 103]) << 56; + + m[13] = ((long) b[offset + 104] & 0xFF); + m[13] |= ((long) b[offset + 105] & 0xFF) << 8; + m[13] |= ((long) b[offset + 106] & 0xFF) << 16; + m[13] |= ((long) b[offset + 107] & 0xFF) << 24; + m[13] |= ((long) b[offset + 108] & 0xFF) << 32; + m[13] |= ((long) b[offset + 109] & 0xFF) << 40; + m[13] |= ((long) b[offset + 110] & 0xFF) << 48; + m[13] |= ((long) b[offset + 111]) << 56; + + m[14] = ((long) b[offset + 112] & 0xFF); + m[14] |= ((long) b[offset + 113] & 0xFF) << 8; + m[14] |= ((long) b[offset + 114] & 0xFF) << 16; + m[14] |= ((long) b[offset + 115] & 0xFF) << 24; + m[14] |= ((long) b[offset + 116] & 0xFF) << 32; + m[14] |= ((long) b[offset + 117] & 0xFF) << 40; + m[14] |= ((long) b[offset + 118] & 0xFF) << 48; + m[14] |= ((long) b[offset + 119]) << 56; + + m[15] = ((long) b[offset + 120] & 0xFF); + m[15] |= ((long) b[offset + 121] & 0xFF) << 8; + m[15] |= ((long) b[offset + 122] & 0xFF) << 16; + m[15] |= ((long) b[offset + 123] & 0xFF) << 24; + m[15] |= ((long) b[offset + 124] & 0xFF) << 32; + m[15] |= ((long) b[offset + 125] & 0xFF) << 40; + m[15] |= ((long) b[offset + 126] & 0xFF) << 48; + m[15] |= ((long) b[offset + 127 ] ) << 56; +// Debug.dumpArray("m @ compress", m); +// +// Debug.dumpArray("h @ compress", h); +// Debug.dumpArray("t @ compress", t); +// Debug.dumpArray("f @ compress", f); + + // set v registers + v[0] = h[0]; + v[1] = h[1]; + v[2] = h[2]; + v[3] = h[3]; + v[4] = h[4]; + v[5] = h[5]; + v[6] = h[6]; + v[7] = h[7]; + v[8] = 0x6a09e667f3bcc908L; + v[9] = 0xbb67ae8584caa73bL; + v[10] = 0x3c6ef372fe94f82bL; + v[11] = 0xa54ff53a5f1d36f1L; + v[12] = t[0] ^ 0x510e527fade682d1L; + v[13] = t[1] ^ 0x9b05688c2b3e6c1fL; + v[14] = f[0] ^ 0x1f83d9abfb41bd6bL; + v[15] = f[1] ^ 0x5be0cd19137e2179L; + +// Debug.dumpArray("v @ compress", v); + // the rounds + // REVU: let's try unrolling this again TODO do & bench + for (int r = 0; r < 12; r++) { + + /** G (r, 0, 0, 4, 8, 12); */ + + v[0] = v[0] + v[4] + m[sig_g00[r]]; + v[12] ^= v[0]; + v[12] = (v[12] << 32) | (v[12] >>> 32); + v[8] = v[8] + v[12]; + v[4] ^= v[8]; + v[4] = (v[4] >>> 24) | (v[4] << 40); + v[0] = v[0] + v[4] + m[sig_g01[r]]; + v[12] ^= v[0]; + v[12] = (v[12] >>> 16) | (v[12] << 48); + v[8] = v[8] + v[12]; + v[4] ^= v[8]; + v[4] = (v[4] << 1) | (v[4] >>> 63); + + /** G (r, 1, 1, 5, 9, 13); */ + + v[1] = v[1] + v[5] + m[sig_g10[r]]; + v[13] ^= v[1]; + v[13] = (v[13] << 32) | (v[13] >>> 32); + v[9] = v[9] + v[13]; + v[5] ^= v[9]; + v[5] = (v[5] >>> 24) | (v[5] << 40); + v[1] = v[1] + v[5] + m[sig_g11[r]]; + v[13] ^= v[1]; + v[13] = (v[13] >>> 16) | (v[13] << 48); + v[9] = v[9] + v[13]; + v[5] ^= v[9]; + v[5] = (v[5] << 1) | (v[5] >>> 63); + + /** G (r, 2, 2, 6, 10, 14); */ + + v[2] = v[2] + v[6] + m[sig_g20[r]]; + v[14] ^= v[2]; + v[14] = (v[14] << 32) | (v[14] >>> 32); + v[10] = v[10] + v[14]; + v[6] ^= v[10]; + v[6] = (v[6] >>> 24) | (v[6] << 40); + v[2] = v[2] + v[6] + m[sig_g21[r]]; + v[14] ^= v[2]; + v[14] = (v[14] >>> 16) | (v[14] << 48); + v[10] = v[10] + v[14]; + v[6] ^= v[10]; + v[6] = (v[6] << 1) | (v[6] >>> 63); + + /** G (r, 3, 3, 7, 11, 15); */ + + v[3] = v[3] + v[7] + m[sig_g30[r]]; + v[15] ^= v[3]; + v[15] = (v[15] << 32) | (v[15] >>> 32); + v[11] = v[11] + v[15]; + v[7] ^= v[11]; + v[7] = (v[7] >>> 24) | (v[7] << 40); + v[3] = v[3] + v[7] + m[sig_g31[r]]; + v[15] ^= v[3]; + v[15] = (v[15] >>> 16) | (v[15] << 48); + v[11] = v[11] + v[15]; + v[7] ^= v[11]; + v[7] = (v[7] << 1) | (v[7] >>> 63); + + /** G (r, 4, 0, 5, 10, 15); */ + + v[0] = v[0] + v[5] + m[sig_g40[r]]; + v[15] ^= v[0]; + v[15] = (v[15] << 32) | (v[15] >>> 32); + v[10] = v[10] + v[15]; + v[5] ^= v[10]; + v[5] = (v[5] >>> 24) | (v[5] << 40); + v[0] = v[0] + v[5] + m[sig_g41[r]]; + v[15] ^= v[0]; + v[15] = (v[15] >>> 16) | (v[15] << 48); + v[10] = v[10] + v[15]; + v[5] ^= v[10]; + v[5] = (v[5] << 1) | (v[5] >>> 63); + + /** G (r, 5, 1, 6, 11, 12); */ + + v[1] = v[1] + v[6] + m[sig_g50[r]]; + v[12] ^= v[1]; + v[12] = (v[12] << 32) | (v[12] >>> 32); + v[11] = v[11] + v[12]; + v[6] ^= v[11]; + v[6] = (v[6] >>> 24) | (v[6] << 40); + v[1] = v[1] + v[6] + +m[sig_g51[r]]; + v[12] ^= v[1]; + v[12] = (v[12] >>> 16) | (v[12] << 48); + v[11] = v[11] + v[12]; + v[6] ^= v[11]; + v[6] = (v[6] << 1) | (v[6] >>> 63); + + /** G (r, 6, 2, 7, 8, 13); */ + + v[2] = v[2] + v[7] + m[sig_g60[r]]; + v[13] ^= v[2]; + v[13] = (v[13] << 32) | (v[13] >>> 32); + v[8] = v[8] + v[13]; + v[7] ^= v[8]; + v[7] = (v[7] >>> 24) | (v[7] << 40); + v[2] = v[2] + v[7] + m[sig_g61[r]]; + v[13] ^= v[2]; + v[13] = (v[13] >>> 16) | (v[13] << 48); + v[8] = v[8] + v[13]; + v[7] ^= v[8]; + v[7] = (v[7] << 1) | (v[7] >>> 63); + + /** G (r, 7, 3, 4, 9, 14); */ + + v[3] = v[3] + v[4] + m[sig_g70[r]]; + v[14] ^= v[3]; + v[14] = (v[14] << 32) | (v[14] >>> 32); + v[9] = v[9] + v[14]; + v[4] ^= v[9]; + v[4] = (v[4] >>> 24) | (v[4] << 40); + v[3] = v[3] + v[4] + m[sig_g71[r]]; + v[14] ^= v[3]; + v[14] = (v[14] >>> 16) | (v[14] << 48); + v[9] = v[9] + v[14]; + v[4] ^= v[9]; + v[4] = (v[4] << 1) | (v[4] >>> 63); + } + + // Update state vector h + h[0] ^= v[0] ^ v[8]; + h[1] ^= v[1] ^ v[9]; + h[2] ^= v[2] ^ v[10]; + h[3] ^= v[3] ^ v[11]; + h[4] ^= v[4] ^ v[12]; + h[5] ^= v[5] ^ v[13]; + h[6] ^= v[6] ^ v[14]; + h[ 7] ^= v[7] ^ v[15]; + +// Debug.dumpArray("v @ compress end", v); +// Debug.dumpArray("h @ compress end", h); + /* kaamil */ + } + + //////////////////////////////////////////////////////////////////////// + /// Compression Kernel /////////////////////////////////////////// BEGIN + //////////////////////////////////////////////////////////////////////// + + /** + * a little bit of semantics + */ + interface flag { + int last_block = 0; + int last_node = 1; + } + + //////////////////////////////////////////////////////////////////////// + /// Compression Kernel //////////////////////////////////////////// FINI + //////////////////////////////////////////////////////////////////////// + + /* TEMP - remove at will */ + public static class Debug { + public static void dumpState (Blake2b.Engine e, final String mark) { + System.out.format("-- MARK == @ %s @ ===========\n", mark); + dumpArray("register t", e.t); + dumpArray("register h", e.h); + dumpArray("register f", e.f); + dumpArray("register offset", new long[]{e.buflen}); + System.out.format("-- END MARK =================\n"); + } + public static void dumpArray (final String label, final long[] b) { + System.out.format ( "-- %s -- :\n{\n", label ); + for( int j = 0; j < b.length ; ++j ) { + System.out.format ( " [%2d] : %016X\n", j, b[j]); + } + System.out.format ( "}\n" ); + } + public static void dumpBuffer (final PrintStream out, final String label, final byte[] b) { + dumpBuffer(out, label, b, 0, b.length); + } + public static void dumpBuffer (final PrintStream out, final byte[] b) { + dumpBuffer(out, null, b, 0, b.length); + } + public static void dumpBuffer (final PrintStream out, final byte[] b, final int offset, final int len) { + dumpBuffer(out, null, b, offset, len); + } + public static void dumpBuffer (final PrintStream out, final String label, final byte[] b, final int offset, final int len) { + if(label != null) + out.format ( "-- %s -- :\n", label ); + out.format("{\n ", label); + for( int j = 0; j < len ; ++j ) { + out.format ("%02X", b[j + offset]); + if(j+1 < len) { + if ((j+1)%8==0) out.print("\n "); + else out.print(' '); + } + } + out.format("\n}\n"); + } + } + /* TEMP - remove at will */ + + // --------------------------------------------------------------------- + // Helper for assert error messages + // --------------------------------------------------------------------- + public static final class Assert { + public final static String exclusiveUpperBound = "'%s' %d is >= %d"; + public final static String inclusiveUpperBound = "'%s' %d is > %d"; + public final static String exclusiveLowerBound = "'%s' %d is <= %d"; + public final static String inclusiveLowerBound = "'%s' %d is < %d"; + static String assertFail(final String name, final T v, final String err, final T spec) { + new Exception().printStackTrace(); + return String.format(err, name, v, spec); + } + } + // --------------------------------------------------------------------- + // Little Endian Codecs (inlined in the compressor) + /* + * impl note: these are not library funcs and used in hot loops, so no + * null or bounds checks are performed. For our purposes, this is OK. + */ + // --------------------------------------------------------------------- + + public static class LittleEndian { + private static final byte[] hex_digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + private static final byte[] HEX_digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + /** @return hex rep of byte (lower case). */ + static public String toHexStr (final byte[] b) { + return toHexStr (b, false); // because String class is slower. + } + static public String toHexStr (final byte[] b, boolean upperCase) { + final int len = b.length; + final byte[] digits = new byte[ len * 2 ]; + final byte[] hex_rep = upperCase ? HEX_digits : hex_digits ; + for (int i = 0; i < len; i++) { + digits [ i*2 ] = hex_rep [ (byte) (b[i] >> 4 & 0x0F) ]; + digits [ i*2+1 ] = hex_rep [ (byte) (b[i] & 0x0F) ]; + } + return new String(digits); + } + public static int readInt (final byte[] b, int off) { + int v0 + = ((int)b [ off++ ] & 0xFF ); + v0 |= ((int)b [ off++ ] & 0xFF ) << 8; + v0 |= ((int)b [ off++ ] & 0xFF ) << 16; + v0 |= ((int)b [ off ] ) << 24; + return v0; + } + /** Little endian - byte[] to long */ + public static long readLong (final byte[] b, int off) { + long v0 + = ((long)b [ off++ ] & 0xFF ); + v0 |= ((long)b [ off++ ] & 0xFF ) << 8; + v0 |= ((long)b [ off++ ] & 0xFF ) << 16; + v0 |= ((long)b [ off++ ] & 0xFF ) << 24; + v0 |= ((long)b [ off++ ] & 0xFF ) << 32; + v0 |= ((long)b [ off++ ] & 0xFF ) << 40; + v0 |= ((long)b [ off++ ] & 0xFF ) << 48; + v0 |= ((long)b [ off ] ) << 56; + return v0; + } + /** */ + /** Little endian - long to byte[] */ + public static void writeLong (long v, final byte[] b, final int off) { + b [ off ] = (byte) v; v >>>= 8; + b [ off + 1 ] = (byte) v; v >>>= 8; + b [ off + 2 ] = (byte) v; v >>>= 8; + b [ off + 3 ] = (byte) v; v >>>= 8; + b [ off + 4 ] = (byte) v; v >>>= 8; + b [ off + 5 ] = (byte) v; v >>>= 8; + b [ off + 6 ] = (byte) v; v >>>= 8; + b [ off + 7 ] = (byte) v; + } + /** Little endian - int to byte[] */ + public static void writeInt (int v, final byte[] b, final int off) { + b [ off ] = (byte) v; v >>>= 8; + b [ off + 1 ] = (byte) v; v >>>= 8; + b [ off + 2 ] = (byte) v; v >>>= 8; + b [ off + 3 ] = (byte) v; + } + } + } + // --------------------------------------------------------------------- + // digest parameter (block) + // --------------------------------------------------------------------- + /** Blake2b configuration parameters block per spec */ + // REVU: need to review a revert back to non-lazy impl TODO: do & bench + public static class Param implements AlgorithmParameterSpec { + /** + * default bytes of Blake2b parameter block + */ + final static byte[] default_bytes = new byte[Spec.param_bytes]; + /** + * default Blake2b h vector + */ + final static long[] default_h = new long[Spec.state_space_len ]; + + /** initialize default_bytes */ + static { + default_bytes [ Xoff.digest_length ] = Default.digest_length; + default_bytes [ Xoff.key_length ] = Default.key_length; + default_bytes [ Xoff.fanout ] = Default.fanout; + default_bytes [ Xoff.depth ] = Default.depth; + /* def. leaf_length is 0 fill and already set by new byte[] */ + /* def. node_offset is 0 fill and already set by new byte[] */ + default_bytes [ Xoff.node_depth ] = Default.node_depth; + default_bytes [ Xoff.inner_length] = Default.inner_length; + /* def. salt is 0 fill and already set by new byte[] */ + /* def. personal is 0 fill and already set by new byte[] */ + } + + static { + default_h [0] = readLong( default_bytes, 0 ); + default_h [1] = readLong( default_bytes, 8 ); + default_h [2] = readLong( default_bytes, 16 ); + default_h [3] = readLong( default_bytes, 24 ); + default_h [4] = readLong( default_bytes, 32 ); + default_h [5] = readLong( default_bytes, 40 ); + default_h [6] = readLong( default_bytes, 48 ); + default_h [7] = readLong( default_bytes, 56 ); + + default_h[0] ^= Spec.IV[0]; + default_h[1] ^= Spec.IV[1]; + default_h[2] ^= Spec.IV[2]; + default_h[3] ^= Spec.IV[3]; + default_h[4] ^= Spec.IV[4]; + default_h[5] ^= Spec.IV[5]; + default_h[6] ^= Spec.IV[6]; + default_h[7] ^= Spec.IV[7]; + } + + /** */ + private final long[] h = new long [ Spec.state_space_len ]; + /** */ + private boolean hasKey = false; + /** not sure how to make this secure - TODO */ + private byte[] key_bytes = null; + /** */ + private byte[] bytes = null; + /** */ + public Param() { + System.arraycopy( default_h, 0, h, 0, Spec.state_space_len ); + } + + /** */ + public long[] initialized_H () { + return h; + } + + /** package only - copy returned - do not use in functional loops */ + public byte[] getBytes() { + lazyInitBytes(); + byte[] copy = new byte[ bytes.length ]; + System.arraycopy( bytes, 0, copy, 0, bytes.length ); + return copy; + } + + final byte getByteParam (final int xoffset) { + byte[] _bytes = bytes; + if(_bytes == null) _bytes = Param.default_bytes; + return _bytes[ xoffset]; + } + + final int getIntParam (final int xoffset) { + byte[] _bytes = bytes; + if(_bytes == null) _bytes = Param.default_bytes; + return readInt ( _bytes, xoffset); + } + + final long getLongParam (final int xoffset) { + byte[] _bytes = bytes; + if(_bytes == null) _bytes = Param.default_bytes; + return readLong ( _bytes, xoffset); + } + + // TODO same for tree params depth, fanout, inner, node-depth, node-offset + public final int getDigestLength() { + return (int) getByteParam ( Xoff.digest_length ); + } + + /* 0-7 inclusive */ + public final Param setDigestLength(int len) { + assert len > 0 : assertFail("len", len, exclusiveLowerBound, 0); + assert len <= Spec.max_digest_bytes : assertFail("len", len, inclusiveUpperBound, Spec.max_digest_bytes); + + lazyInitBytes(); + bytes[Xoff.digest_length] = (byte) len; + h[0] = readLong(bytes, 0); + h[0] ^= Spec.IV[0]; + return this; + } + + public final int getKeyLength() { + return (int) getByteParam(Xoff.key_length); + } + + public final int getFanout() { + return (int) getByteParam(Xoff.fanout); + } + + public final Param setFanout(int fanout) { + assert fanout > 0 : assertFail("fanout", fanout, exclusiveLowerBound, 0); + + lazyInitBytes(); + bytes[Xoff.fanout] = (byte) fanout; + h[0] = readLong(bytes, 0); + h[0] ^= Spec.IV[0]; + return this; + } + + public final int getDepth() { + return (int) getByteParam(Xoff.depth); + } + + public final Param setDepth(int depth) { + assert depth > 0 : assertFail("depth", depth, exclusiveLowerBound, 0); + + lazyInitBytes(); + bytes[Xoff.depth] = (byte) depth; + h[0] = readLong(bytes, 0); + h[0] ^= Spec.IV[0]; + return this; + } + + public final int getLeafLength() { + return getIntParam(Xoff.leaf_length); + } + + public final Param setLeafLength(int leaf_length) { + assert leaf_length >= 0 : assertFail("leaf_length", leaf_length, inclusiveLowerBound, 0); + + lazyInitBytes(); + writeInt(leaf_length, bytes, Xoff.leaf_length); + h[0] = readLong(bytes, 0); + h[0] ^= Spec.IV[0]; + return this; + } + + public final long getNodeOffset() { + return getLongParam ( Xoff.node_offset); + } + + /* 8-15 inclusive */ + public final Param setNodeOffset(long node_offset) { + assert node_offset >= 0 : assertFail("node_offset", node_offset, inclusiveLowerBound, 0); + + lazyInitBytes(); + writeLong(node_offset, bytes, Xoff.node_offset); + h[1] = readLong(bytes, Xoff.node_offset); + h[1] ^= Spec.IV[1]; + return this; + } + + public final int getNodeDepth() { + return (int) getByteParam(Xoff.node_depth); + } + + /* 16-23 inclusive */ + public final Param setNodeDepth(int node_depth) { + assert node_depth >= 0 : assertFail("node_depth", node_depth, inclusiveLowerBound, 0); + + lazyInitBytes(); + bytes[Xoff.node_depth] = (byte) node_depth; + h[2] = readLong(bytes, Xoff.node_depth); + h[2] ^= Spec.IV[2]; + h[3] = readLong(bytes, Xoff.node_depth + 8); + h[3] ^= Spec.IV[3]; + return this; + } + + public final int getInnerLength() { + return (int) getByteParam(Xoff.inner_length ); + } + + public final Param setInnerLength(int inner_length) { + assert inner_length >= 0 : assertFail("inner_length", inner_length, inclusiveLowerBound, 0); + + lazyInitBytes(); + bytes[Xoff.inner_length] = (byte) inner_length; + h[2] = readLong(bytes, Xoff.node_depth); + h[2] ^= Spec.IV[2]; + h[3] = readLong(bytes, Xoff.node_depth + 8); + h[3] ^= Spec.IV[3]; + return this; + } + + public final boolean hasKey() { + return this.hasKey; + } + + @Override + public Param clone() { + final Param clone = new Param(); + System.arraycopy(this.h, 0, clone.h, 0, h.length); + clone.lazyInitBytes(); + System.arraycopy(this.bytes, 0, clone.bytes, 0, this.bytes.length); + + if (this.hasKey) { + clone.hasKey = this.hasKey; + clone.key_bytes = new byte[Spec.max_key_bytes * 2]; + System.arraycopy(this.key_bytes, 0, clone.key_bytes, 0, this.key_bytes.length); + } + return clone; + } + + //////////////////////////////////////////////////////////////////////// + /// lazy setters - write directly to the bytes image of param block //// + //////////////////////////////////////////////////////////////////////// + final void lazyInitBytes() { + if (bytes == null) { + bytes = new byte[Spec.param_bytes]; + System.arraycopy(Param.default_bytes, 0, bytes, 0, Spec.param_bytes); + } + } + + public final Param setKey(final Key key) { + assert key != null : "key is null"; + final byte[] keybytes = key.getEncoded(); + assert keybytes != null : "key.encoded() is null"; + + return this.setKey(keybytes); + } + + public final Param setKey(final byte[] key) { + assert key != null : "key is null"; + assert key.length >= 0 : assertFail("key.length", key.length, inclusiveUpperBound, 0); + assert key.length <= Spec.max_key_bytes : assertFail("key.length", key.length, inclusiveUpperBound, Spec.max_key_bytes); + + // zeropad keybytes + this.key_bytes = new byte[Spec.max_key_bytes * 2]; + System.arraycopy(key, 0, this.key_bytes, 0, key.length); + lazyInitBytes(); + bytes[Xoff.key_length] = (byte) key.length; // checked c ref; this is correct + h[0] = readLong(bytes, 0); + h[0] ^= Spec.IV[0]; + this.hasKey = true; + return this; + } + + /* 32-47 inclusive */ + public final Param setSalt(final byte[] salt) { + assert salt != null : "salt is null"; + assert salt.length <= Spec.max_salt_bytes : assertFail("salt.length", salt.length, inclusiveUpperBound, Spec.max_salt_bytes); + + lazyInitBytes(); + Arrays.fill ( bytes, Xoff.salt, Xoff.salt + Spec.max_salt_bytes, (byte)0); + System.arraycopy( salt, 0, bytes, Xoff.salt, salt.length ); + h[ 4 ] = readLong( bytes, Xoff.salt ); + h[ 4 ] ^= Spec.IV [ 4 ]; + h[ 5 ] = readLong( bytes, Xoff.salt + 8 ); + h[ 5 ] ^= Spec.IV [ 5 ]; + return this; + } + + /* 48-63 inclusive */ + public final Param setPersonal(byte[] personal) { + assert personal != null : "personal is null"; + assert personal.length <= Spec.max_personalization_bytes : assertFail("personal.length", personal.length, inclusiveUpperBound, Spec.max_personalization_bytes); + + lazyInitBytes(); + Arrays.fill(bytes, Xoff.personal, Xoff.personal + Spec.max_personalization_bytes, (byte) 0); + System.arraycopy(personal, 0, bytes, Xoff.personal, personal.length); + h[6] = readLong(bytes, Xoff.personal); + h[6] ^= Spec.IV[6]; + h[7] = readLong(bytes, Xoff.personal + 8); + h[7] ^= Spec.IV[7]; + return this; + } + + /* 24-31 masked by reserved and remain unchanged */ + + interface Xoff { + int digest_length = 0; + int key_length = 1; + int fanout = 2; + int depth = 3; + int leaf_length = 4; + int node_offset = 8; + int node_depth = 16; + int inner_length = 17; + int reserved = 18; + int salt = 32; + int personal = 48; + } + + public interface Default { + byte digest_length = Spec.max_digest_bytes; + byte key_length = 0; + byte fanout = 1; + byte depth = 1; + int leaf_length = 0; + long node_offset = 0; + byte node_depth = 0; + byte inner_length = 0; + } + //////////////////////////////////////////////////////////////////////// + /// lazy setters /////////////////////////////////////////////////// END + //////////////////////////////////////////////////////////////////////// + } +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/exception/Argon2Exception.java b/src/ext/plantuml/com/at/gadermaier/argon2/exception/Argon2Exception.java new file mode 100644 index 000000000..6e1b677d5 --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/exception/Argon2Exception.java @@ -0,0 +1,13 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2.exception; + +/* dislike checked exceptions */ +class Argon2Exception extends RuntimeException { + Argon2Exception(String message) { + super(message); + } +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/exception/Argon2InvalidParameterException.java b/src/ext/plantuml/com/at/gadermaier/argon2/exception/Argon2InvalidParameterException.java new file mode 100644 index 000000000..6a6678972 --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/exception/Argon2InvalidParameterException.java @@ -0,0 +1,12 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2.exception; + +public class Argon2InvalidParameterException extends Argon2Exception{ + public Argon2InvalidParameterException(String message) { + super(message); + } +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/model/Argon2Type.java b/src/ext/plantuml/com/at/gadermaier/argon2/model/Argon2Type.java new file mode 100644 index 000000000..546051a16 --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/model/Argon2Type.java @@ -0,0 +1,10 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2.model; + +public enum Argon2Type { + Argon2d, Argon2i, Argon2id; +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/model/Block.java b/src/ext/plantuml/com/at/gadermaier/argon2/model/Block.java new file mode 100644 index 000000000..a7418dd9d --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/model/Block.java @@ -0,0 +1,81 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2.model; + + +import static ext.plantuml.com.at.gadermaier.argon2.Constants.ARGON2_BLOCK_SIZE; +import static ext.plantuml.com.at.gadermaier.argon2.Constants.ARGON2_QWORDS_IN_BLOCK; + +import java.util.Arrays; + +import ext.plantuml.com.at.gadermaier.argon2.Util; + +public class Block { + + /* 128 * 8 Byte QWords */ + public long[] v; + + public Block() { + v = new long[ARGON2_QWORDS_IN_BLOCK]; + } + + public void fromBytes(byte[] input) { + assert (input.length == ARGON2_BLOCK_SIZE); + + for (int i = 0; i < v.length; i++) { + byte[] slice = Arrays.copyOfRange(input, i * 8, (i + 1) * 8); + v[i] = Util.littleEndianBytesToLong(slice); + } + } + + public byte[] toBytes() { + byte[] result = new byte[ARGON2_BLOCK_SIZE]; + + for (int i = 0; i < v.length; i++) { + byte[] bytes = Util.longToLittleEndianBytes(v[i]); + System.arraycopy(bytes, 0, result, i * bytes.length, bytes.length); + } + + return result; + } + + public void copyBlock(Block other) { + System.arraycopy(other.v, 0, v, 0, v.length); + } + + public void xor(Block b1, Block b2) { + for (int i = 0; i < v.length; i++) { + v[i] = b1.v[i] ^ b2.v[i]; + } + } + + public void xor(Block b1, Block b2, Block b3) { + for (int i = 0; i < v.length; i++) { + v[i] = b1.v[i] ^ b2.v[i] ^ b3.v[i]; + } + } + + public void xorWith(Block other) { + for (int i = 0; i < v.length; i++) { + v[i] = v[i] ^ other.v[i]; + } + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + for (long value : v) { + result.append(Util.bytesToHexString(Util.longToLittleEndianBytes(value))); + } + + return result.toString(); + } + + void clear() { + Arrays.fill(v, 0); + } +} + diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/model/Instance.java b/src/ext/plantuml/com/at/gadermaier/argon2/model/Instance.java new file mode 100644 index 000000000..807654466 --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/model/Instance.java @@ -0,0 +1,88 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2.model; + +import static ext.plantuml.com.at.gadermaier.argon2.Constants.ARGON2_SYNC_POINTS; + +import ext.plantuml.com.at.gadermaier.argon2.Argon2; + +public class Instance { + + public Block[] memory; + private int version; + private int iterations; + private int segmentLength; + private int laneLength; + private int lanes; + + private Argon2Type type; + + public Instance(Argon2 argon2) { + this.version = argon2.getVersion(); + this.iterations = argon2.getIterations(); + this.lanes = argon2.getLanes(); + this.type = argon2.getType(); + + /* 2. Align memory size */ + /* Minimum memoryBlocks = 8L blocks, where L is the number of lanes */ + int memoryBlocks = argon2.getMemory(); + + if (memoryBlocks < 2 * ARGON2_SYNC_POINTS * argon2.getLanes()) { + memoryBlocks = 2 * ARGON2_SYNC_POINTS * argon2.getLanes(); + } + + this.segmentLength = memoryBlocks / (argon2.getLanes() * ARGON2_SYNC_POINTS); + this.laneLength = segmentLength * ARGON2_SYNC_POINTS; + /* Ensure that all segments have equal length */ + memoryBlocks = segmentLength * (argon2.getLanes() * ARGON2_SYNC_POINTS); + + initMemory(memoryBlocks); + } + + private void initMemory(int memoryBlocks) { + this.memory = new Block[memoryBlocks]; + + for (int i = 0; i < memory.length; i++) { + memory[i] = new Block(); + } + } + + public void clear() { + for (Block b : memory) { + b.clear(); + } + + memory = null; + } + + public Block[] getMemory() { + return memory; + } + + public int getVersion() { + return version; + } + + public int getIterations() { + return iterations; + } + + public int getSegmentLength() { + return segmentLength; + } + + public int getLaneLength() { + return laneLength; + } + + public int getLanes() { + return lanes; + } + + public Argon2Type getType() { + return type; + } +} diff --git a/src/ext/plantuml/com/at/gadermaier/argon2/model/Position.java b/src/ext/plantuml/com/at/gadermaier/argon2/model/Position.java new file mode 100644 index 000000000..bf052ba3e --- /dev/null +++ b/src/ext/plantuml/com/at/gadermaier/argon2/model/Position.java @@ -0,0 +1,22 @@ +/* This file is taken from + https://github.com/andreas1327250/argon2-java + + Original Author: Andreas Gadermaier + */ +package ext.plantuml.com.at.gadermaier.argon2.model; + +public class Position { + + public int pass; + public int lane; + public int slice; + public int index; + + public Position(int pass, int lane, int slice, int index) { + this.pass = pass; + this.lane = lane; + this.slice = slice; + this.index = index; + } +} + diff --git a/src/net/sourceforge/plantuml/dedication/0.png b/src/net/sourceforge/plantuml/dedication/0.png deleted file mode 100644 index a03ee156b..000000000 Binary files a/src/net/sourceforge/plantuml/dedication/0.png and /dev/null differ diff --git a/src/net/sourceforge/plantuml/dedication/1.png b/src/net/sourceforge/plantuml/dedication/1.png deleted file mode 100644 index 91edd9a89..000000000 Binary files a/src/net/sourceforge/plantuml/dedication/1.png and /dev/null differ diff --git a/src/net/sourceforge/plantuml/dedication/2.png b/src/net/sourceforge/plantuml/dedication/2.png deleted file mode 100644 index c37934ee8..000000000 Binary files a/src/net/sourceforge/plantuml/dedication/2.png and /dev/null differ diff --git a/src/net/sourceforge/plantuml/dedication/514816d583044efbd336882227deb822194ff63e3bdc3cf707a01f17770d5a6a.png b/src/net/sourceforge/plantuml/dedication/514816d583044efbd336882227deb822194ff63e3bdc3cf707a01f17770d5a6a.png new file mode 100644 index 000000000..8bf20e266 Binary files /dev/null and b/src/net/sourceforge/plantuml/dedication/514816d583044efbd336882227deb822194ff63e3bdc3cf707a01f17770d5a6a.png differ diff --git a/src/net/sourceforge/plantuml/dedication/835ff5d643b58cd35a20db6480071d05751aa6a0e01da78662ceafd0161f3f5e.png b/src/net/sourceforge/plantuml/dedication/835ff5d643b58cd35a20db6480071d05751aa6a0e01da78662ceafd0161f3f5e.png new file mode 100644 index 000000000..85c96fb5b Binary files /dev/null and b/src/net/sourceforge/plantuml/dedication/835ff5d643b58cd35a20db6480071d05751aa6a0e01da78662ceafd0161f3f5e.png differ diff --git a/src/net/sourceforge/plantuml/dedication/DecoderInputStream.java b/src/net/sourceforge/plantuml/dedication/DecoderInputStream.java deleted file mode 100644 index 0b572230f..000000000 --- a/src/net/sourceforge/plantuml/dedication/DecoderInputStream.java +++ /dev/null @@ -1,104 +0,0 @@ -/* ======================================================================== - * PlantUML : a free UML diagram generator - * ======================================================================== - * - * (C) Copyright 2009-2020, Arnaud Roques - * - * Project Info: http://plantuml.com - * - * If you like this project or if you find it useful, you can support us at: - * - * http://plantuml.com/patreon (only 1$ per month!) - * http://plantuml.com/paypal - * - * This file is part of PlantUML. - * - * PlantUML is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * PlantUML distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - * License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - * - * - * Original Author: Arnaud Roques - * - * - */ -package net.sourceforge.plantuml.dedication; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Random; - -public class DecoderInputStream extends InputStream { - - private final TurningBytes message; - private final TurningBytes sha; - private final Random rnd; - private final InputStream source; - - public DecoderInputStream(InputStream source, String s) { - this.source = source; - try { - final byte[] text = s.getBytes("UTF-8"); - final byte[] key = getSignatureSha512(text); - this.rnd = new Random(getSeed(key)); - this.message = new TurningBytes(text); - this.sha = new TurningBytes(key); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - throw new UnsupportedOperationException(e); - } - } - - private static byte[] getSignatureSha512(byte[] bytes) { - try { - final MessageDigest msgDigest = MessageDigest.getInstance("SHA-512"); - msgDigest.update(bytes); - return msgDigest.digest(); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - throw new UnsupportedOperationException(e); - } - } - - private long getSeed(byte[] bytes) { - long result = 17; - for (byte b : bytes) { - result = result * 37 + b; - } - return result; - } - - private byte getNextByte() { - return (byte) (rnd.nextInt() ^ message.nextByte() ^ sha.nextByte()); - } - - @Override - public void close() throws IOException { - source.close(); - } - - @Override - public int read() throws IOException { - int b = source.read(); - if (b == -1) { - return -1; - } - b = (b ^ getNextByte()) & 0xFF; - return b; - } - -} diff --git a/src/net/sourceforge/plantuml/dedication/Dedication.java b/src/net/sourceforge/plantuml/dedication/Dedication.java index c272d6e3a..a8686c273 100644 --- a/src/net/sourceforge/plantuml/dedication/Dedication.java +++ b/src/net/sourceforge/plantuml/dedication/Dedication.java @@ -36,69 +36,16 @@ package net.sourceforge.plantuml.dedication; import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Method; import java.math.BigInteger; -import javax.imageio.stream.ImageInputStream; +public interface Dedication { -import net.sourceforge.plantuml.security.ImageIO; - -public class Dedication { - - private final String name; public static final int SIZE = 512; - public Dedication(String name) { - this.name = name; - } - static public final BigInteger E = new BigInteger("47"); static public final BigInteger N = new BigInteger( "64194259632025692228025828504368542164501926620236990850309916606915924860847417702229807236946186163298479808527077315212362810246237044147835839820235668271044023359607622658694578433933680627840319408427732468918341837133798296090069295727323673222224923200718714534955390633175683720810506099934813509605263799234445827953809462431871169282281822048299576307847441008670575692934434087522877910989584374673170522742162366773143807761599862833698229067475807108264396251702152180676841544743258182370105404479387062985271422237607462447989728490398294623785717593446941673706569352249533885603771123718557406286501161336667835919957553680522213067630956498293529840163155604109185561515875171125161872265975088797712442352939352686113608345330266855433849127812528823634773975825170679786399199082599910532761710473383280738663105826045325480095451410448217715495894688594898541182351588505292424154550388343455540760277051977859647543838445735549451966254020972172982014944475678385523833120793348365125754234511467512831686599126674298367512469557219326026525667529348508876650236597163509336304607610284488623800062157659286940214435134423619711736992281071131245654755167288438258292694799131521268600284444731890784171372171309"); - public InputStream getInputStream(String keepLetter) throws IOException { - final InputStream tmp = PSystemDedication.class.getResourceAsStream(name + ".png"); - final InputStream step1 = new DecoderInputStream(tmp, keepLetter); - final QBlocks rsa = QBlocks.readFrom(step1, SIZE + 1); - final QBlocks decrypted = rsa.change(E, N); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - decrypted.writeTo(baos, SIZE); - baos.close(); - return new ByteArrayInputStream(baos.toByteArray()); - } - - public static BufferedImage getBufferedImage(InputStream is) { - try { - final Class clVP8Decoder = Class.forName("net.sourceforge.plantuml.webp.VP8Decoder"); - final Object vp8Decoder = clVP8Decoder.newInstance(); - // final VP8Decoder vp8Decoder = new VP8Decoder(); - final Method decodeFrame = clVP8Decoder.getMethod("decodeFrame", ImageInputStream.class); - final ImageInputStream iis = ImageIO.createImageInputStream(is); - decodeFrame.invoke(vp8Decoder, iis); - // vp8Decoder.decodeFrame(iis); - iis.close(); - final Object frame = clVP8Decoder.getMethod("getFrame").invoke(vp8Decoder); - return (BufferedImage) frame.getClass().getMethod("getBufferedImage").invoke(frame); - // final VP8Frame frame = vp8Decoder.getFrame(); - // return frame.getBufferedImage(); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - public BufferedImage getBufferedImage(String keepLetter) { - try { - final InputStream is = getInputStream(keepLetter); - return getBufferedImage(is); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } + public BufferedImage getImage(String sentence); } diff --git a/src/net/sourceforge/plantuml/dedication/DedicationCrypted.java b/src/net/sourceforge/plantuml/dedication/DedicationCrypted.java new file mode 100644 index 000000000..9681d410e --- /dev/null +++ b/src/net/sourceforge/plantuml/dedication/DedicationCrypted.java @@ -0,0 +1,119 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.dedication; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.math.BigInteger; + +import net.sourceforge.plantuml.utils.MTRandom; + +public class DedicationCrypted implements Dedication { + + private final String argon2; + private final BigInteger pq; + private final byte crypted[]; + private final int tinyHash; + private String solution; + + private long next = 0L; + + public DedicationCrypted(byte crypted[], int tinyHash, String argon2, BigInteger pq) { + this.crypted = crypted; + this.pq = pq; + this.argon2 = argon2; + this.tinyHash = tinyHash; + } + + public synchronized BufferedImage getImage(final String sentence) { + if (sentence.length() < 40) { + return null; + } + + try { + if (solution == null || sentence.equals(this.solution) == false) { + if (System.currentTimeMillis() < next) { + return null; + } + final int tinyHash = Noise.shortHash(sentence.getBytes("UTF-8"), N.toByteArray()); + if (this.tinyHash != tinyHash) { + return null; + } + this.next = System.currentTimeMillis() + 5000L; + } + + final byte[] hash1 = Noise.computeArgon2bytes(sentence.getBytes("UTF-8"), + (pq.toString(35) + sentence).getBytes("UTF-8")); + final byte[] hash2 = Noise.computeArgon2bytes(sentence.getBytes("UTF-8"), + (pq.toString(36) + sentence).getBytes("UTF-8")); + + final BlumBlumShub rndBBS = new BlumBlumShub(pq, hash1); + final MTRandom rndMT = new MTRandom(hash2); + + byte[] current = crypted.clone(); + Noise.shuffle(current, rndMT); + Noise.xor(current, rndBBS); + Noise.xor(current, sentence.getBytes("UTF-8")); + + Noise.shuffle(current, rndMT); + + final RBlocks init = RBlocks.readFrom(current, 513); + final RBlocks decoded = init.change(E, N); + + current = decoded.toByteArray(512); + + Noise.shuffle(current, rndMT); + Noise.xor(current, rndBBS); + + final String argon = Noise.computeArgon2String(current, (pq.toString(34) + sentence).getBytes("UTF-8")); + + if (this.argon2.equals(argon) == false) { + return null; + } + Noise.shuffle(current, rndMT); + current = Noise.reverse(current, rndMT.nextInt()); + + final BufferedImage img = PSystemDedication.getBufferedImage(new ByteArrayInputStream(current)); + this.solution = sentence; + return img; + } catch (Throwable t) { + t.printStackTrace(); + return null; + } + + } + +} diff --git a/src/net/sourceforge/plantuml/dedication/NoisyInputStream.java b/src/net/sourceforge/plantuml/dedication/DedicationSimple.java similarity index 58% rename from src/net/sourceforge/plantuml/dedication/NoisyInputStream.java rename to src/net/sourceforge/plantuml/dedication/DedicationSimple.java index d99a894eb..3b0056d03 100644 --- a/src/net/sourceforge/plantuml/dedication/NoisyInputStream.java +++ b/src/net/sourceforge/plantuml/dedication/DedicationSimple.java @@ -35,38 +35,41 @@ */ package net.sourceforge.plantuml.dedication; -import java.io.IOException; -import java.io.InputStream; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; -import net.sourceforge.plantuml.utils.MTRandom; +public class DedicationSimple implements Dedication { -public class NoisyInputStream extends InputStream { + private final byte crypted[]; + private final String sentence; - private final MTRandom rnd; - private final InputStream source; - - public NoisyInputStream(InputStream source, byte[] pass) { - this.source = source; - this.rnd = new MTRandom(pass); + public DedicationSimple(byte crypted[], String sentence) { + this.crypted = crypted; + this.sentence = sentence; } - private byte getNextByte() { - return (byte) rnd.nextInt(); - } - - @Override - public void close() throws IOException { - source.close(); - } - - @Override - public int read() throws IOException { - int b = source.read(); - if (b == -1) { - return -1; + public synchronized BufferedImage getImage(String sentence) { + if (same(this.sentence, sentence) == false) { + return null; } - b = (b ^ getNextByte()) & 0xFF; - return b; + + try { + byte[] current = crypted.clone(); + + final RBlocks init = RBlocks.readFrom(current, 513); + final RBlocks decoded = init.change(E, N); + current = decoded.toByteArray(512); + return PSystemDedication.getBufferedImage(new ByteArrayInputStream(current)); + } catch (Throwable t) { + t.printStackTrace(); + return null; + } + } + + private boolean same(String s1, String s2) { + s1 = s1.replaceAll("[^\\p{L}0-9]+", ""); + s2 = s2.replaceAll("[^\\p{L}0-9]+", ""); + return s1.equalsIgnoreCase(s2); } } diff --git a/src/net/sourceforge/plantuml/dedication/Dedications.java b/src/net/sourceforge/plantuml/dedication/Dedications.java index ee78ca4e5..d44ecffa9 100644 --- a/src/net/sourceforge/plantuml/dedication/Dedications.java +++ b/src/net/sourceforge/plantuml/dedication/Dedications.java @@ -35,79 +35,60 @@ */ package net.sourceforge.plantuml.dedication; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; -import net.sourceforge.plantuml.SignatureUtils; +import net.sourceforge.plantuml.FileUtils; public class Dedications { - private static final Map normal = new HashMap(); - private static final Map crypted = new HashMap(); + private static final List all = new ArrayList(); static { - addNormal("Write your own dedication!", "dedication"); - addNormal("linux_china", "linux_china"); - addNormal("ARKBAN", "arkban"); - addNormal("Boundaries allow discipline to create true strength", "boundaries"); - addNormal("Thank you, Dr. Chet. I wouldn't be where I am without you", "dr_chet"); - addNormal("Ben and Jen 2020", "ben"); - addCrypted("0", "pOhci6rKgPXw32AeYXhOpSY0suoauHq5VUSwFqHLHsLYgSO6WaJ7BW5vtHBAoU6ePbcW7d8Flx99MWjPSKQTDm00"); - addCrypted("1", "LTxN3hdnhSJ515qcA7IQ841axt4GXfUd3n2wgNirYCdLnyX2360Gv1OEOnJ1-gwFzRW5B3HAqLBkR6Ge0WW_Z000"); - addCrypted("2", "lZqLduj4j1yRqSfAvkhbqVpqK8diklatiFeenDUXSdna9bKYQTzdS264YfUBScUVDYCp2Vcq04updoN98RwxE000"); + + try { + all.add(new DedicationSimple(load("dedication"), "Write your own dedication!")); + all.add(new DedicationSimple(load("linux_china"), "linux_china")); + all.add(new DedicationSimple(load("arkban"), "arkban")); + all.add(new DedicationSimple(load("boundaries"), "Boundaries allow discipline to create true strength")); + all.add(new DedicationSimple(load("dr_chet"), "Thank you, Dr. Chet. I wouldn't be where I am without you")); + all.add(new DedicationSimple(load("ben"), "Ben and Jen 2020")); + all.add(secret(5, "835ff5d643b58cd35a20db6480071d05751aa6a0e01da78662ceafd0161f3f5e", new BigInteger( + "1182423723677118831606503500858825217076578422970565964857326298418401529955036896808663335300684244453386039908536275400945824932191521017102701344437753036730900076162922741167523337650578479960119614237031234925702200473053235777"))); + all.add(secret(3, "514816d583044efbd336882227deb822194ff63e3bdc3cf707a01f17770d5a6a", new BigInteger( + "538955952645999836068094511687012232127213955837942782605199622268460518023083462090291844640318324475656060087513198129259364840841077651829017347845508167869708224054456044836844382437974410757740941102771969965334031780041648873"))); + } catch (IOException e) { + e.printStackTrace(); + } } - private static void addNormal(String sentence, String name) { - normal.put(keepLetter(sentence), new Dedication(name)); + private static DedicationCrypted secret(int tiny, String sig, BigInteger pq) throws IOException { + return new DedicationCrypted(load(sig), tiny, sig, pq); } - private static void addCrypted(String name, String contentKey) { - crypted.put(contentKey, new Dedication(name)); + private static byte[] load(String name) throws IOException { + final InputStream tmp = PSystemDedication.class.getResourceAsStream(name + ".png"); + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + FileUtils.copyInternal(tmp, baos, true); + return baos.toByteArray(); } private Dedications() { } - public static Dedication get(String line) { - final String keepLetter = keepLetter(line); - final Dedication result = normal.get(keepLetter); - if (result != null) { - return result; - } - for (Map.Entry ent : crypted.entrySet()) { - final Dedication dedication = ent.getValue(); - InputStream is = null; - try { - is = dedication.getInputStream(keepLetter); - final String signature = SignatureUtils.getSignatureSha512(is); - if (signature.equals(ent.getKey())) { - return dedication; - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (is != null) - is.close(); - } catch (Exception e) { - e.printStackTrace(); - } + public synchronized static BufferedImage get(String line) { + for (Dedication dedication : all) { + final BufferedImage image = dedication.getImage(line); + if (image != null) { + return image; } - } return null; } - public static String keepLetter(String s) { - final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < s.length(); i++) { - final char c = s.charAt(i); - if (Character.isLetterOrDigit(c)) { - sb.append(c); - } - } - return sb.toString(); - } - } diff --git a/src/net/sourceforge/plantuml/dedication/Noise.java b/src/net/sourceforge/plantuml/dedication/Noise.java index b6bae6cf6..9ec2dfc41 100644 --- a/src/net/sourceforge/plantuml/dedication/Noise.java +++ b/src/net/sourceforge/plantuml/dedication/Noise.java @@ -35,6 +35,80 @@ */ package net.sourceforge.plantuml.dedication; +import ext.plantuml.com.at.gadermaier.argon2.Argon2; +import ext.plantuml.com.at.gadermaier.argon2.Argon2Factory; +import ext.plantuml.com.at.gadermaier.argon2.model.Argon2Type; +import net.sourceforge.plantuml.utils.MTRandom; + public class Noise { + private static Argon2 argon2(byte[] buffer, byte[] salt) { + final Argon2 argon = Argon2Factory.create() // + .setType(Argon2Type.Argon2id) // + .setMemory(8) // + .setSalt(salt.clone()) // + .setIterations(50) // + .setPassword(buffer.clone()); + argon.hashNow(); + return argon; + } + + public static String computeArgon2String(byte[] buffer, byte[] salt) { + return argon2(buffer, salt).getOutputString(); + } + + public static byte[] computeArgon2bytes(byte[] buffer, byte[] salt) { + return argon2(buffer, salt).getOutput(); + } + + public static int shortHash(byte[] buffer, byte[] salt) { + final byte hash[] = argon2(buffer, salt).getOutput(); + int result = 0; + for (byte b : hash) { + final int b1 = b & 0x0F; + final int b2 = (b & 0xF0) >> 4; + result ^= b1 ^ b2; + } + return result; + } + + public static void shuffle(byte[] buffer, MTRandom rnd) { + for (int i = 0; i < buffer.length; i++) { + final int r1 = rnd.nextInt(); + final int r2 = rnd.nextInt(); + final int a = Math.abs(r1) % buffer.length; + final int b = Math.abs(r2) % buffer.length; + final byte tmp = buffer[a]; + buffer[a] = buffer[b]; + buffer[b] = tmp; + } + } + + public static void xor(byte[] buffer, byte[] xor) { + for (int i = 0; i < buffer.length; i++) { + buffer[i] ^= xor[i % xor.length]; + } + } + + public static void xor(byte[] buffer, BlumBlumShub rnd) { + for (int i = 0; i < buffer.length; i++) { + final byte mask = (byte) (rnd.nextRnd(8) & 0xFF); + buffer[i] = (byte) (buffer[i] ^ mask); + } + } + + public static byte[] reverse(byte[] buffer, int delta) { + delta = Math.abs(delta) % buffer.length; + final byte result[] = new byte[buffer.length]; + for (int i = 0; i < buffer.length; i++) + result[i] = buffer[(buffer.length - 1 - i + delta) % buffer.length]; + return result; + } + + + + + + + } diff --git a/src/net/sourceforge/plantuml/dedication/PSystemDedication.java b/src/net/sourceforge/plantuml/dedication/PSystemDedication.java index 82bf01fc3..17906d799 100644 --- a/src/net/sourceforge/plantuml/dedication/PSystemDedication.java +++ b/src/net/sourceforge/plantuml/dedication/PSystemDedication.java @@ -53,22 +53,20 @@ import net.sourceforge.plantuml.ugraphic.UImage; public class PSystemDedication extends PlainDiagram { - private final Dedication dedication; - private final String keepLetter; + private final BufferedImage img; - public PSystemDedication(Dedication dedication, String keepLetter) { - this.dedication = dedication; - this.keepLetter = keepLetter; + public PSystemDedication(BufferedImage img) { + this.img = img; + if (img == null) { + throw new IllegalArgumentException(); + } } @Override protected UDrawable getRootDrawable(FileFormatOption fileFormatOption) { return new UDrawable() { public void drawU(UGraphic ug) { - final BufferedImage bufferedImage = dedication.getBufferedImage(keepLetter); - if (bufferedImage != null) { - ug.draw(new UImage(new PixelImage(bufferedImage, AffineTransformType.TYPE_BILINEAR))); - } + ug.draw(new UImage(new PixelImage(img, AffineTransformType.TYPE_BILINEAR))); } }; } diff --git a/src/net/sourceforge/plantuml/dedication/PSystemDedicationFactory.java b/src/net/sourceforge/plantuml/dedication/PSystemDedicationFactory.java index 987a7c3e7..43e16f6e3 100644 --- a/src/net/sourceforge/plantuml/dedication/PSystemDedicationFactory.java +++ b/src/net/sourceforge/plantuml/dedication/PSystemDedicationFactory.java @@ -35,6 +35,8 @@ */ package net.sourceforge.plantuml.dedication; +import java.awt.image.BufferedImage; + import net.sourceforge.plantuml.AbstractPSystem; import net.sourceforge.plantuml.command.PSystemSingleLineFactory; @@ -42,9 +44,9 @@ public class PSystemDedicationFactory extends PSystemSingleLineFactory { @Override protected AbstractPSystem executeLine(String line) { - final Dedication dedication = Dedications.get(line); + final BufferedImage dedication = Dedications.get(line); if (dedication != null) { - return new PSystemDedication(dedication, Dedications.keepLetter(line)); + return new PSystemDedication(dedication); } return null; } diff --git a/src/net/sourceforge/plantuml/dedication/arkban.png b/src/net/sourceforge/plantuml/dedication/arkban.png index 7ddc8131d..ab073d541 100644 Binary files a/src/net/sourceforge/plantuml/dedication/arkban.png and b/src/net/sourceforge/plantuml/dedication/arkban.png differ diff --git a/src/net/sourceforge/plantuml/dedication/ben.png b/src/net/sourceforge/plantuml/dedication/ben.png index e7756fb6e..ed0177f8f 100644 Binary files a/src/net/sourceforge/plantuml/dedication/ben.png and b/src/net/sourceforge/plantuml/dedication/ben.png differ diff --git a/src/net/sourceforge/plantuml/dedication/boundaries.png b/src/net/sourceforge/plantuml/dedication/boundaries.png index b989556e6..ae7fbd32d 100644 Binary files a/src/net/sourceforge/plantuml/dedication/boundaries.png and b/src/net/sourceforge/plantuml/dedication/boundaries.png differ diff --git a/src/net/sourceforge/plantuml/dedication/dedication.png b/src/net/sourceforge/plantuml/dedication/dedication.png index 0e6b8b280..fe727cebc 100644 Binary files a/src/net/sourceforge/plantuml/dedication/dedication.png and b/src/net/sourceforge/plantuml/dedication/dedication.png differ diff --git a/src/net/sourceforge/plantuml/dedication/dr_chet.png b/src/net/sourceforge/plantuml/dedication/dr_chet.png index 9d9c3930a..5c50730b7 100644 Binary files a/src/net/sourceforge/plantuml/dedication/dr_chet.png and b/src/net/sourceforge/plantuml/dedication/dr_chet.png differ diff --git a/src/net/sourceforge/plantuml/dedication/linux_china.png b/src/net/sourceforge/plantuml/dedication/linux_china.png index 3000b1598..e30928d7a 100644 Binary files a/src/net/sourceforge/plantuml/dedication/linux_china.png and b/src/net/sourceforge/plantuml/dedication/linux_china.png differ diff --git a/src/net/sourceforge/plantuml/project/GanttDiagram.java b/src/net/sourceforge/plantuml/project/GanttDiagram.java index ad9d011b9..cdd223f73 100644 --- a/src/net/sourceforge/plantuml/project/GanttDiagram.java +++ b/src/net/sourceforge/plantuml/project/GanttDiagram.java @@ -271,25 +271,30 @@ public class GanttDiagram extends TitledDiagram implements ToTaskDraw, WithSprit private TimeHeader getTimeHeader() { if (openClose.getCalendar() == null) { - return new TimeHeaderSimple(min, max); + return new TimeHeaderSimple(min, max, getClosedStyle(), getIHtmlColorSet()); } else if (printScale == PrintScale.WEEKLY) { return new TimeHeaderWeekly(getFactorScale(), openClose.getCalendar(), min, max, openClose, colorDays, - colorDaysOfWeek, weekNumberStrategy); + colorDaysOfWeek, weekNumberStrategy, getClosedStyle(), getIHtmlColorSet()); } else if (printScale == PrintScale.MONTHLY) { return new TimeHeaderMonthly(getFactorScale(), openClose.getCalendar(), min, max, openClose, colorDays, - colorDaysOfWeek); + colorDaysOfWeek, getClosedStyle(), getIHtmlColorSet()); } else if (printScale == PrintScale.QUARTERLY) { return new TimeHeaderQuarterly(getFactorScale(), openClose.getCalendar(), min, max, openClose, colorDays, - colorDaysOfWeek); + colorDaysOfWeek, getClosedStyle(), getIHtmlColorSet()); } else if (printScale == PrintScale.YEARLY) { return new TimeHeaderYearly(getFactorScale(), openClose.getCalendar(), min, max, openClose, colorDays, - colorDaysOfWeek); + colorDaysOfWeek, getClosedStyle(), getIHtmlColorSet()); } else { return new TimeHeaderDaily(openClose.getCalendar(), min, max, openClose, colorDays, colorDaysOfWeek, - nameDays, printStart, printEnd); + nameDays, printStart, printEnd, getClosedStyle(), getIHtmlColorSet()); } } + private Style getClosedStyle() { + return StyleSignature.of(SName.root, SName.element, SName.ganttDiagram, SName.closed) + .getMergedStyle(getCurrentStyleBuilder()); + } + private double getTotalHeight(TimeHeader timeHeader) { if (showFootbox) { return totalHeightWithoutFooter + timeHeader.getTimeFooterHeight(); diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeader.java b/src/net/sourceforge/plantuml/project/draw/TimeHeader.java index bb8c123f9..0fc1f7948 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeader.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeader.java @@ -42,6 +42,8 @@ import net.sourceforge.plantuml.graphic.HorizontalAlignment; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.project.time.Day; import net.sourceforge.plantuml.project.timescale.TimeScale; +import net.sourceforge.plantuml.style.PName; +import net.sourceforge.plantuml.style.Style; import net.sourceforge.plantuml.ugraphic.UFont; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.ULine; @@ -62,17 +64,30 @@ public abstract class TimeHeader { return 28; } - protected final HColor veryLightGray = HColorSet.instance().getColorOrWhite("#E0E8E8"); - protected final HColor lightGray = HColorSet.instance().getColorOrWhite("#909898"); - private final TimeScale timeScale; + private final Style style; + private final HColorSet colorSet; + protected final Day min; protected final Day max; - public TimeHeader(Day min, Day max, TimeScale timeScale) { + public TimeHeader(Day min, Day max, TimeScale timeScale, Style style, HColorSet colorSet) { + if (style == null) { + throw new IllegalArgumentException(); + } this.timeScale = timeScale; this.min = min; this.max = max; + this.style = style; + this.colorSet = colorSet; + } + + protected final HColor closedBackgroundColor() { + return style.value(PName.BackGroundColor).asColor(colorSet); + } + + protected final HColor closedFontColor() { + return style.value(PName.FontColor).asColor(colorSet); } public abstract double getTimeHeaderHeight(); diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderCalendar.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderCalendar.java index 636063ceb..a68c9b9e8 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeaderCalendar.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderCalendar.java @@ -41,8 +41,10 @@ import net.sourceforge.plantuml.project.LoadPlanable; import net.sourceforge.plantuml.project.time.Day; import net.sourceforge.plantuml.project.time.DayOfWeek; import net.sourceforge.plantuml.project.timescale.TimeScale; +import net.sourceforge.plantuml.style.Style; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.color.HColor; +import net.sourceforge.plantuml.ugraphic.color.HColorSet; public abstract class TimeHeaderCalendar extends TimeHeader { @@ -51,8 +53,8 @@ public abstract class TimeHeaderCalendar extends TimeHeader { protected final Map colorDaysOfWeek; public TimeHeaderCalendar(Day calendar, Day min, Day max, LoadPlanable defaultPlan, Map colorDays, - Map colorDaysOfWeek, TimeScale timeScale) { - super(min, max, timeScale); + Map colorDaysOfWeek, TimeScale timeScale, Style style, HColorSet colorSet) { + super(min, max, timeScale, style, colorSet); this.defaultPlan = defaultPlan; this.colorDays = colorDays; this.colorDaysOfWeek = colorDaysOfWeek; @@ -89,7 +91,7 @@ public abstract class TimeHeaderCalendar extends TimeHeader { back = backDoW; } if (back == null && defaultPlan.getLoadAt(wink) == 0) { - back = veryLightGray; + back = closedBackgroundColor(); } if (back == null) { if (pending != null) diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderDaily.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderDaily.java index 0591796bd..afb53f974 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeaderDaily.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderDaily.java @@ -43,10 +43,12 @@ import net.sourceforge.plantuml.project.time.Day; import net.sourceforge.plantuml.project.time.DayOfWeek; import net.sourceforge.plantuml.project.time.MonthYear; import net.sourceforge.plantuml.project.timescale.TimeScaleDaily; +import net.sourceforge.plantuml.style.Style; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.ULine; import net.sourceforge.plantuml.ugraphic.UTranslate; import net.sourceforge.plantuml.ugraphic.color.HColor; +import net.sourceforge.plantuml.ugraphic.color.HColorSet; import net.sourceforge.plantuml.ugraphic.color.HColorUtils; public class TimeHeaderDaily extends TimeHeaderCalendar { @@ -63,8 +65,10 @@ public class TimeHeaderDaily extends TimeHeaderCalendar { private final Map nameDays; public TimeHeaderDaily(Day calendar, Day min, Day max, LoadPlanable defaultPlan, Map colorDays, - Map colorDaysOfWeek, Map nameDays, Day printStart, Day printEnd) { - super(calendar, min, max, defaultPlan, colorDays, colorDaysOfWeek, new TimeScaleDaily(calendar, printStart)); + Map colorDaysOfWeek, Map nameDays, Day printStart, Day printEnd, + Style style, HColorSet colorSet) { + super(calendar, min, max, defaultPlan, colorDays, colorDaysOfWeek, new TimeScaleDaily(calendar, printStart), + style, colorSet); this.nameDays = nameDays; } @@ -111,7 +115,7 @@ public class TimeHeaderDaily extends TimeHeaderCalendar { private HColor getTextBackColor(Day wink) { if (defaultPlan.getLoadAt(wink) <= 0) { - return lightGray; + return closedFontColor(); } return HColorUtils.BLACK; } diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderMonthly.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderMonthly.java index 67c5142c8..4fbc4f51e 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeaderMonthly.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderMonthly.java @@ -43,10 +43,12 @@ import net.sourceforge.plantuml.project.time.Day; import net.sourceforge.plantuml.project.time.DayOfWeek; import net.sourceforge.plantuml.project.time.MonthYear; import net.sourceforge.plantuml.project.timescale.TimeScaleCompressed; +import net.sourceforge.plantuml.style.Style; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.ULine; import net.sourceforge.plantuml.ugraphic.UTranslate; import net.sourceforge.plantuml.ugraphic.color.HColor; +import net.sourceforge.plantuml.ugraphic.color.HColorSet; import net.sourceforge.plantuml.ugraphic.color.HColorUtils; public class TimeHeaderMonthly extends TimeHeaderCalendar { @@ -60,9 +62,9 @@ public class TimeHeaderMonthly extends TimeHeaderCalendar { } public TimeHeaderMonthly(double scale, Day calendar, Day min, Day max, LoadPlanable defaultPlan, Map colorDays, - Map colorDaysOfWeek) { + Map colorDaysOfWeek, Style style, HColorSet colorSet) { super(calendar, min, max, defaultPlan, colorDays, colorDaysOfWeek, - new TimeScaleCompressed(calendar, scale)); + new TimeScaleCompressed(calendar, scale), style, colorSet); } @Override diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderQuarterly.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderQuarterly.java index 45f7502d3..df2d4a68a 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeaderQuarterly.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderQuarterly.java @@ -43,10 +43,12 @@ import net.sourceforge.plantuml.project.time.Day; import net.sourceforge.plantuml.project.time.DayOfWeek; import net.sourceforge.plantuml.project.time.MonthYear; import net.sourceforge.plantuml.project.timescale.TimeScaleCompressed; +import net.sourceforge.plantuml.style.Style; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.ULine; import net.sourceforge.plantuml.ugraphic.UTranslate; import net.sourceforge.plantuml.ugraphic.color.HColor; +import net.sourceforge.plantuml.ugraphic.color.HColorSet; import net.sourceforge.plantuml.ugraphic.color.HColorUtils; public class TimeHeaderQuarterly extends TimeHeaderCalendar { @@ -59,10 +61,10 @@ public class TimeHeaderQuarterly extends TimeHeaderCalendar { return 16 + 13 - 1; } - public TimeHeaderQuarterly(double scale, Day calendar, Day min, Day max, LoadPlanable defaultPlan, Map colorDays, - Map colorDaysOfWeek) { - super(calendar, min, max, defaultPlan, colorDays, colorDaysOfWeek, - new TimeScaleCompressed(calendar, scale)); + public TimeHeaderQuarterly(double scale, Day calendar, Day min, Day max, LoadPlanable defaultPlan, + Map colorDays, Map colorDaysOfWeek, Style style, HColorSet colorSet) { + super(calendar, min, max, defaultPlan, colorDays, colorDaysOfWeek, new TimeScaleCompressed(calendar, scale), + style, colorSet); } @Override @@ -126,9 +128,9 @@ public class TimeHeaderQuarterly extends TimeHeaderCalendar { } drawVbar(ug, getTimeScale().getEndingPosition(max), 0, 12); } - + private String quarter(Day day) { - return "Q" + (( day.month().ordinal() + 3 ) / 3); + return "Q" + ((day.month().ordinal() + 3) / 3); } private void printYear(UGraphic ug, MonthYear monthYear, double start, double end) { diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderSimple.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderSimple.java index 2c120c967..5d4f1442c 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeaderSimple.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderSimple.java @@ -42,9 +42,11 @@ import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.project.time.Day; import net.sourceforge.plantuml.project.timescale.TimeScale; import net.sourceforge.plantuml.project.timescale.TimeScaleWink; +import net.sourceforge.plantuml.style.Style; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.ULine; import net.sourceforge.plantuml.ugraphic.UTranslate; +import net.sourceforge.plantuml.ugraphic.color.HColorSet; import net.sourceforge.plantuml.ugraphic.color.HColorUtils; public class TimeHeaderSimple extends TimeHeader { @@ -66,8 +68,8 @@ public class TimeHeaderSimple extends TimeHeader { return 0; } - public TimeHeaderSimple(Day min, Day max) { - super(min, max, new TimeScaleWink()); + public TimeHeaderSimple(Day min, Day max, Style style, HColorSet colorSet) { + super(min, max, new TimeScaleWink(), style, colorSet); } private void drawSmallVlinesDay(UGraphic ug, TimeScale timeScale, double totalHeightWithoutFooter) { diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderWeekly.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderWeekly.java index 091f8c157..5a3909568 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeaderWeekly.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderWeekly.java @@ -44,10 +44,12 @@ import net.sourceforge.plantuml.project.time.DayOfWeek; import net.sourceforge.plantuml.project.time.MonthYear; import net.sourceforge.plantuml.project.time.WeekNumberStrategy; import net.sourceforge.plantuml.project.timescale.TimeScaleCompressed; +import net.sourceforge.plantuml.style.Style; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.ULine; import net.sourceforge.plantuml.ugraphic.UTranslate; import net.sourceforge.plantuml.ugraphic.color.HColor; +import net.sourceforge.plantuml.ugraphic.color.HColorSet; import net.sourceforge.plantuml.ugraphic.color.HColorUtils; public class TimeHeaderWeekly extends TimeHeaderCalendar { @@ -63,8 +65,10 @@ public class TimeHeaderWeekly extends TimeHeaderCalendar { } public TimeHeaderWeekly(double scale, Day calendar, Day min, Day max, LoadPlanable defaultPlan, - Map colorDays, Map colorDaysOfWeek, WeekNumberStrategy weekNumberStrategy) { - super(calendar, min, max, defaultPlan, colorDays, colorDaysOfWeek, new TimeScaleCompressed(calendar, scale)); + Map colorDays, Map colorDaysOfWeek, WeekNumberStrategy weekNumberStrategy, + Style style, HColorSet colorSet) { + super(calendar, min, max, defaultPlan, colorDays, colorDaysOfWeek, new TimeScaleCompressed(calendar, scale), + style, colorSet); this.weekNumberStrategy = weekNumberStrategy; } diff --git a/src/net/sourceforge/plantuml/project/draw/TimeHeaderYearly.java b/src/net/sourceforge/plantuml/project/draw/TimeHeaderYearly.java index 1b9e2f44e..c2583dcb2 100644 --- a/src/net/sourceforge/plantuml/project/draw/TimeHeaderYearly.java +++ b/src/net/sourceforge/plantuml/project/draw/TimeHeaderYearly.java @@ -43,10 +43,12 @@ import net.sourceforge.plantuml.project.time.Day; import net.sourceforge.plantuml.project.time.DayOfWeek; import net.sourceforge.plantuml.project.time.MonthYear; import net.sourceforge.plantuml.project.timescale.TimeScaleCompressed; +import net.sourceforge.plantuml.style.Style; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.ULine; import net.sourceforge.plantuml.ugraphic.UTranslate; import net.sourceforge.plantuml.ugraphic.color.HColor; +import net.sourceforge.plantuml.ugraphic.color.HColorSet; import net.sourceforge.plantuml.ugraphic.color.HColorUtils; public class TimeHeaderYearly extends TimeHeaderCalendar { @@ -60,8 +62,9 @@ public class TimeHeaderYearly extends TimeHeaderCalendar { } public TimeHeaderYearly(double scale, Day calendar, Day min, Day max, LoadPlanable defaultPlan, - Map colorDays, Map colorDaysOfWeek) { - super(calendar, min, max, defaultPlan, colorDays, colorDaysOfWeek, new TimeScaleCompressed(calendar, scale)); + Map colorDays, Map colorDaysOfWeek, Style style, HColorSet colorSet) { + super(calendar, min, max, defaultPlan, colorDays, colorDaysOfWeek, new TimeScaleCompressed(calendar, scale), + style, colorSet); } @Override diff --git a/src/net/sourceforge/plantuml/style/SName.java b/src/net/sourceforge/plantuml/style/SName.java index 4e0284e7f..5ea3a1d9b 100644 --- a/src/net/sourceforge/plantuml/style/SName.java +++ b/src/net/sourceforge/plantuml/style/SName.java @@ -54,6 +54,7 @@ public enum SName { class_, // clickable, // cloud, // + closed, // collection, // collections, // component, // diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageLollipopInterfaceEye1.java b/src/net/sourceforge/plantuml/svek/image/EntityImageLollipopInterfaceEye1.java index 1c625eae4..875bad9c3 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageLollipopInterfaceEye1.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageLollipopInterfaceEye1.java @@ -53,8 +53,8 @@ import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.svek.AbstractEntityImage; import net.sourceforge.plantuml.svek.Bibliotekon; -import net.sourceforge.plantuml.svek.SvekLine; import net.sourceforge.plantuml.svek.ShapeType; +import net.sourceforge.plantuml.svek.SvekLine; import net.sourceforge.plantuml.ugraphic.UEllipse; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UStroke; diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageNote.java b/src/net/sourceforge/plantuml/svek/image/EntityImageNote.java index 79ad6eddc..c910e7728 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageNote.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageNote.java @@ -71,8 +71,8 @@ import net.sourceforge.plantuml.style.SName; import net.sourceforge.plantuml.style.Style; import net.sourceforge.plantuml.style.StyleSignature; import net.sourceforge.plantuml.svek.AbstractEntityImage; -import net.sourceforge.plantuml.svek.SvekLine; import net.sourceforge.plantuml.svek.ShapeType; +import net.sourceforge.plantuml.svek.SvekLine; import net.sourceforge.plantuml.svek.SvekNode; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UGraphicStencil; diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageState.java b/src/net/sourceforge/plantuml/svek/image/EntityImageState.java index 8672656fe..51ebd158f 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageState.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageState.java @@ -37,13 +37,9 @@ package net.sourceforge.plantuml.svek.image; import java.awt.geom.Dimension2D; -import net.sourceforge.plantuml.ColorParam; import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.FontParam; import net.sourceforge.plantuml.ISkinParam; -import net.sourceforge.plantuml.LineConfigurable; -import net.sourceforge.plantuml.SkinParamUtils; -import net.sourceforge.plantuml.Url; import net.sourceforge.plantuml.creole.CreoleMode; import net.sourceforge.plantuml.cucadiagram.Display; import net.sourceforge.plantuml.cucadiagram.IEntity; @@ -52,24 +48,16 @@ import net.sourceforge.plantuml.graphic.FontConfiguration; import net.sourceforge.plantuml.graphic.HorizontalAlignment; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; -import net.sourceforge.plantuml.graphic.color.ColorType; -import net.sourceforge.plantuml.svek.AbstractEntityImage; -import net.sourceforge.plantuml.svek.ShapeType; -import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UEllipse; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UGroupType; import net.sourceforge.plantuml.ugraphic.ULine; -import net.sourceforge.plantuml.ugraphic.URectangle; import net.sourceforge.plantuml.ugraphic.UStroke; import net.sourceforge.plantuml.ugraphic.UTranslate; -import net.sourceforge.plantuml.ugraphic.color.HColor; -public class EntityImageState extends AbstractEntityImage { +public class EntityImageState extends EntityImageStateCommon { - final private TextBlock desc; final private TextBlock fields; - final private Url url; final private static int MIN_WIDTH = 50; final private static int MIN_HEIGHT = 50; @@ -81,25 +69,13 @@ public class EntityImageState extends AbstractEntityImage { final static private double smallMarginX = 7; final static private double smallMarginY = 4; - final private LineConfigurable lineConfig; - public EntityImageState(IEntity entity, ISkinParam skinParam) { super(entity, skinParam); - this.lineConfig = entity; + final Stereotype stereotype = entity.getStereotype(); + this.withSymbol = stereotype != null && stereotype.isWithOOSymbol(); - - this.desc = entity.getDisplay().create8(new FontConfiguration(getSkinParam(), FontParam.STATE, stereotype), - HorizontalAlignment.CENTER, skinParam, CreoleMode.FULL, skinParam.wrapWidth()); - -// Display list = Display.empty(); -// for (Member att : entity.getBodier().getFieldsToDisplay()) { -// list = list.addAll(Display.getWithNewlines(att.getDisplay(true))); -// } final Display list = Display.create(entity.getBodier().getRawBody()); - - this.url = entity.getUrl99(); - this.fields = list.create8(new FontConfiguration(getSkinParam(), FontParam.STATE_ATTRIBUTE, stereotype), HorizontalAlignment.LEFT, skinParam, CreoleMode.FULL, skinParam.wrapWidth()); @@ -125,28 +101,11 @@ public class EntityImageState extends AbstractEntityImage { final Dimension2D dimTotal = calculateDimension(stringBounder); final Dimension2D dimDesc = desc.calculateDimension(stringBounder); - final double widthTotal = dimTotal.getWidth(); - final double heightTotal = dimTotal.getHeight(); - final Shadowable rect = new URectangle(widthTotal, heightTotal).rounded(CORNER); - if (getSkinParam().shadowing(getEntity().getStereotype())) { - rect.setDeltaShadow(4); - } - - HColor classBorder = lineConfig.getColors(getSkinParam()).getColor(ColorType.LINE); - if (classBorder == null) { - classBorder = SkinParamUtils.getColor(getSkinParam(), getStereo(), ColorParam.stateBorder); - } - ug = ug.apply(getStroke()).apply(classBorder); - HColor backcolor = getEntity().getColors(getSkinParam()).getColor(ColorType.BACK); - if (backcolor == null) { - backcolor = SkinParamUtils.getColor(getSkinParam(), getStereo(), ColorParam.stateBackground); - } - ug = ug.apply(backcolor.bg()); - - ug.draw(rect); + ug = applyColor(ug); + ug.draw(getShape(dimTotal)); final double yLine = MARGIN + dimDesc.getHeight() + MARGIN_LINE; - ug.apply(UTranslate.dy(yLine)).draw(ULine.hline(widthTotal)); + ug.apply(UTranslate.dy(yLine)).draw(ULine.hline(dimTotal.getWidth())); ug = ug.apply(new UStroke()); @@ -156,7 +115,7 @@ public class EntityImageState extends AbstractEntityImage { drawSymbol(ug, xSymbol, ySymbol); } - final double xDesc = (widthTotal - dimDesc.getWidth()) / 2; + final double xDesc = (dimTotal.getWidth() - dimDesc.getWidth()) / 2; final double yDesc = MARGIN; desc.drawU(ug.apply(new UTranslate(xDesc, yDesc))); @@ -170,14 +129,6 @@ public class EntityImageState extends AbstractEntityImage { ug.closeGroup(); } - private UStroke getStroke() { - UStroke stroke = lineConfig.getColors(getSkinParam()).getSpecificLineStroke(); - if (stroke == null) { - stroke = new UStroke(1.5); - } - return stroke; - } - public static void drawSymbol(UGraphic ug, double xSymbol, double ySymbol) { xSymbol -= 4 * smallRadius + smallLine + smallMarginX; ySymbol -= 2 * smallRadius + smallMarginY; @@ -187,8 +138,4 @@ public class EntityImageState extends AbstractEntityImage { ug.apply(new UTranslate(xSymbol + 2 * smallRadius, ySymbol + smallLine)).draw(ULine.hline(smallLine)); } - public ShapeType getShapeType() { - return ShapeType.ROUND_RECTANGLE; - } - } diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageState2.java b/src/net/sourceforge/plantuml/svek/image/EntityImageState2.java index adf31d6c4..203a16f2f 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageState2.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageState2.java @@ -63,22 +63,15 @@ import net.sourceforge.plantuml.ugraphic.color.HColor; public class EntityImageState2 extends AbstractEntityImage { final private Url url; - - final private LineConfigurable lineConfig; + // final private LineConfigurable lineConfig; private final TextBlock asSmall; public EntityImageState2(ILeaf entity, ISkinParam skinParam) { super(entity, skinParam); - this.lineConfig = entity; + // this.lineConfig = entity; final Stereotype stereotype = entity.getStereotype(); -// Display list = Display.empty(); -// for (Member att : entity.getBodier().getFieldsToDisplay()) { -// list = list.addAll(Display.getWithNewlines(att.getDisplay(true))); -// } - // final Display list = Display.create(entity.getBodier().getRawBody()); - final USymbol symbol = USymbol.FRAME; HColor backcolor = getEntity().getColors(getSkinParam()).getColor(ColorType.BACK); diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageStateCommon.java b/src/net/sourceforge/plantuml/svek/image/EntityImageStateCommon.java new file mode 100644 index 000000000..1b5e3c048 --- /dev/null +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageStateCommon.java @@ -0,0 +1,115 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.svek.image; + +import java.awt.geom.Dimension2D; + +import net.sourceforge.plantuml.ColorParam; +import net.sourceforge.plantuml.FontParam; +import net.sourceforge.plantuml.ISkinParam; +import net.sourceforge.plantuml.LineConfigurable; +import net.sourceforge.plantuml.SkinParamUtils; +import net.sourceforge.plantuml.Url; +import net.sourceforge.plantuml.creole.CreoleMode; +import net.sourceforge.plantuml.cucadiagram.IEntity; +import net.sourceforge.plantuml.cucadiagram.Stereotype; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HorizontalAlignment; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.graphic.color.ColorType; +import net.sourceforge.plantuml.svek.AbstractEntityImage; +import net.sourceforge.plantuml.svek.ShapeType; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.URectangle; +import net.sourceforge.plantuml.ugraphic.UStroke; +import net.sourceforge.plantuml.ugraphic.color.HColor; + +public abstract class EntityImageStateCommon extends AbstractEntityImage { + + final protected TextBlock desc; + final protected Url url; + + final protected LineConfigurable lineConfig; + + public EntityImageStateCommon(IEntity entity, ISkinParam skinParam) { + super(entity, skinParam); + + this.lineConfig = entity; + final Stereotype stereotype = entity.getStereotype(); + + this.desc = entity.getDisplay().create8(new FontConfiguration(getSkinParam(), FontParam.STATE, stereotype), + HorizontalAlignment.CENTER, skinParam, CreoleMode.FULL, skinParam.wrapWidth()); + this.url = entity.getUrl99(); + + } + + final protected UStroke getStroke() { + UStroke stroke = lineConfig.getColors(getSkinParam()).getSpecificLineStroke(); + if (stroke == null) { + stroke = new UStroke(1.5); + } + return stroke; + } + + final public ShapeType getShapeType() { + return ShapeType.ROUND_RECTANGLE; + } + + final protected URectangle getShape(final Dimension2D dimTotal) { + final URectangle rect = new URectangle(dimTotal).rounded(CORNER); + if (getSkinParam().shadowing(getEntity().getStereotype())) { + rect.setDeltaShadow(4); + } + return rect; + } + + final protected UGraphic applyColor(UGraphic ug) { + + HColor classBorder = lineConfig.getColors(getSkinParam()).getColor(ColorType.LINE); + if (classBorder == null) { + classBorder = SkinParamUtils.getColor(getSkinParam(), getStereo(), ColorParam.stateBorder); + } + ug = ug.apply(getStroke()).apply(classBorder); + HColor backcolor = getEntity().getColors(getSkinParam()).getColor(ColorType.BACK); + if (backcolor == null) { + backcolor = SkinParamUtils.getColor(getSkinParam(), getStereo(), ColorParam.stateBackground); + } + ug = ug.apply(backcolor.bg()); + + return ug; + } + +} diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageStateEmptyDescription.java b/src/net/sourceforge/plantuml/svek/image/EntityImageStateEmptyDescription.java index 23e1e758d..aa025fa49 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageStateEmptyDescription.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageStateEmptyDescription.java @@ -37,51 +37,20 @@ package net.sourceforge.plantuml.svek.image; import java.awt.geom.Dimension2D; -import net.sourceforge.plantuml.ColorParam; import net.sourceforge.plantuml.Dimension2DDouble; -import net.sourceforge.plantuml.FontParam; import net.sourceforge.plantuml.ISkinParam; -import net.sourceforge.plantuml.SkinParamUtils; -import net.sourceforge.plantuml.Url; -import net.sourceforge.plantuml.creole.CreoleMode; import net.sourceforge.plantuml.cucadiagram.IEntity; -import net.sourceforge.plantuml.cucadiagram.Stereotype; -import net.sourceforge.plantuml.graphic.FontConfiguration; -import net.sourceforge.plantuml.graphic.HorizontalAlignment; import net.sourceforge.plantuml.graphic.StringBounder; -import net.sourceforge.plantuml.graphic.TextBlock; -import net.sourceforge.plantuml.graphic.color.ColorType; -import net.sourceforge.plantuml.svek.AbstractEntityImage; -import net.sourceforge.plantuml.svek.ShapeType; -import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UGraphic; -import net.sourceforge.plantuml.ugraphic.URectangle; -import net.sourceforge.plantuml.ugraphic.UStroke; import net.sourceforge.plantuml.ugraphic.UTranslate; -import net.sourceforge.plantuml.ugraphic.color.HColor; -public class EntityImageStateEmptyDescription extends AbstractEntityImage { - - final private TextBlock desc; - final private Url url; +public class EntityImageStateEmptyDescription extends EntityImageStateCommon { final private static int MIN_WIDTH = 50; final private static int MIN_HEIGHT = 40; public EntityImageStateEmptyDescription(IEntity entity, ISkinParam skinParam) { super(entity, skinParam); - final Stereotype stereotype = entity.getStereotype(); - - this.desc = entity.getDisplay().create8(new FontConfiguration(getSkinParam(), FontParam.STATE, stereotype), - HorizontalAlignment.CENTER, skinParam, CreoleMode.FULL, skinParam.wrapWidth()); - -// Display list = Display.empty(); -// for (Member att : entity.getBodier().getFieldsToDisplay()) { -// list = list.addAll(Display.getWithNewlines(att.getDisplay(true))); -// } -// final Display list = Display.create(entity.getBodier().getRawBody()); - - this.url = entity.getUrl99(); } @@ -99,23 +68,11 @@ public class EntityImageStateEmptyDescription extends AbstractEntityImage { final Dimension2D dimTotal = calculateDimension(stringBounder); final Dimension2D dimDesc = desc.calculateDimension(stringBounder); - final double widthTotal = dimTotal.getWidth(); - final double heightTotal = dimTotal.getHeight(); - final Shadowable rect = new URectangle(widthTotal, heightTotal).rounded(CORNER); - if (getSkinParam().shadowing(getEntity().getStereotype())) { - rect.setDeltaShadow(4); - } + ug = applyColor(ug); + ug.draw(getShape(dimTotal)); - ug = ug.apply(new UStroke(1.5)) - .apply(SkinParamUtils.getColor(getSkinParam(), getStereo(), ColorParam.stateBorder)); - HColor backcolor = getEntity().getColors(getSkinParam()).getColor(ColorType.BACK); - if (backcolor == null) { - backcolor = SkinParamUtils.getColor(getSkinParam(), getStereo(), ColorParam.stateBackground); - } - ug = ug.apply(backcolor.bg()); - ug.draw(rect); - final double xDesc = (widthTotal - dimDesc.getWidth()) / 2; - final double yDesc = (heightTotal - dimDesc.getHeight()) / 2; + final double xDesc = (dimTotal.getWidth() - dimDesc.getWidth()) / 2; + final double yDesc = (dimTotal.getHeight() - dimDesc.getHeight()) / 2; desc.drawU(ug.apply(new UTranslate(xDesc, yDesc))); if (url != null) { @@ -123,8 +80,4 @@ public class EntityImageStateEmptyDescription extends AbstractEntityImage { } } - public ShapeType getShapeType() { - return ShapeType.ROUND_RECTANGLE; - } - } diff --git a/src/net/sourceforge/plantuml/version/PSystemVersion.java b/src/net/sourceforge/plantuml/version/PSystemVersion.java index 8f57cca90..fdf0066e3 100644 --- a/src/net/sourceforge/plantuml/version/PSystemVersion.java +++ b/src/net/sourceforge/plantuml/version/PSystemVersion.java @@ -34,6 +34,8 @@ */ package net.sourceforge.plantuml.version; +import static net.sourceforge.plantuml.graphic.GraphicPosition.BACKGROUND_CORNER_BOTTOM_RIGHT; + import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; @@ -47,7 +49,7 @@ import net.sourceforge.plantuml.PlainStringsDiagram; import net.sourceforge.plantuml.Run; import net.sourceforge.plantuml.core.DiagramDescription; import net.sourceforge.plantuml.cucadiagram.dot.GraphvizUtils; -import net.sourceforge.plantuml.dedication.Dedication; +import net.sourceforge.plantuml.dedication.PSystemDedication; import net.sourceforge.plantuml.preproc.ImportedFiles; import net.sourceforge.plantuml.preproc.Stdlib; import net.sourceforge.plantuml.preproc2.PreprocessorUtils; @@ -57,8 +59,6 @@ import net.sourceforge.plantuml.security.SecurityProfile; import net.sourceforge.plantuml.security.SecurityUtils; import net.sourceforge.plantuml.svek.GraphvizCrash; -import static net.sourceforge.plantuml.graphic.GraphicPosition.BACKGROUND_CORNER_BOTTOM_RIGHT; - public class PSystemVersion extends PlainStringsDiagram { PSystemVersion(boolean withImage, List args) { @@ -126,7 +126,7 @@ public class PSystemVersion extends PlainStringsDiagram { private static BufferedImage getImageWebp(final String name) { try { final InputStream is = PSystemVersion.class.getResourceAsStream(name); - final BufferedImage image = Dedication.getBufferedImage(is); + final BufferedImage image = PSystemDedication.getBufferedImage(is); is.close(); return image; } catch (IOException e) { diff --git a/src/net/sourceforge/plantuml/version/Version.java b/src/net/sourceforge/plantuml/version/Version.java index 237c51db7..0f2f87632 100644 --- a/src/net/sourceforge/plantuml/version/Version.java +++ b/src/net/sourceforge/plantuml/version/Version.java @@ -44,7 +44,7 @@ public class Version { private static final int MAJOR_SEPARATOR = 1000000; public static int version() { - return 1202104; + return 1202105; } public static int versionPatched() { @@ -80,7 +80,7 @@ public class Version { } public static int beta() { - final int beta = 5; + final int beta = 0; return beta; } @@ -93,7 +93,7 @@ public class Version { } public static long compileTime() { - return 1617526179012L; + return 1619349628741L; } public static String compileTimeString() { diff --git a/svg/default.css b/svg/default.css deleted file mode 100644 index aecd589ec..000000000 --- a/svg/default.css +++ /dev/null @@ -1,3 +0,0 @@ -.elem {cursor: pointer;} -.elem, .link {opacity: 0.3;} -.elem.selected, .link.selected {opacity: 1;} \ No newline at end of file diff --git a/svg/default.js b/svg/default.js deleted file mode 100644 index 27da2a695..000000000 --- a/svg/default.js +++ /dev/null @@ -1,110 +0,0 @@ -function addItemToMapOfLists(mapOfLists, name, item) { - // mapOfLists = { - // 'key1': [item1, item2, ...], - // 'key2': [item3, item4, ...], - // } - if (mapOfLists[name].length > 0) { - if (!mapOfLists[name].includes(item)) { - mapOfLists[name].push(item); - } - } else { - mapOfLists[name] = [item]; - } -} - -function main() { - let elems = Array.from(document.getElementsByClassName('elem')); - let links = Array.from(document.getElementsByClassName('link')); - - let elemsMap = {}; - let linkedElems = {}; - let linkedLinks = {}; - - elems.forEach(elem => { - let name = elem.classList[1]; - elemsMap[name] = elem; - linkedElems[name] = []; - linkedLinks[name] = []; - }); - - links.forEach(link => { - let name1 = link.classList[1]; - let name2 = link.classList[2]; - - if (elemsMap[name1]) { - if (elemsMap[name2]) { - let elem1 = elemsMap[name1]; - let elem2 = elemsMap[name2]; - - addItemToMapOfLists(linkedElems, name1, elem2); - addItemToMapOfLists(linkedElems, name2, elem1); - - addItemToMapOfLists(linkedLinks, name1, link); - addItemToMapOfLists(linkedLinks, name2, link); - } - } - }); - - let selectedElems = []; - let selectedLinks = []; - let selectedElemName = null; - - function clearSelected() { - selectedElems.forEach(item => { - item.classList.remove('selected'); - }); - selectedElems = []; - - selectedLinks.forEach(item => { - item.classList.remove('selected'); - }); - selectedLinks = []; - } - - function selectAll() { - selectedElemName = null; - - selectedElems = Array.from(elems); - selectedElems.forEach(item => { - item.classList.add('selected'); - }); - - selectedLinks = Array.from(links); - selectedLinks.forEach(item => { - item.classList.add('selected'); - }); - } - - function selectElem(elemName) { - if (elemName === selectedElemName) { - selectAll(); - - } else { - clearSelected(); - selectedElemName = elemName; - - elemsMap[elemName].classList.add('selected'); - selectedElems.push(elemsMap[elemName]); - - linkedElems[elemName].forEach(linkedElem => { - selectedElems.push(linkedElem); - linkedElem.classList.add('selected'); - }); - - linkedLinks[elemName].forEach(linkedLink => { - selectedLinks.push(linkedLink); - linkedLink.classList.add('selected'); - }); - } - } - - Object.keys(elemsMap).forEach(name => { - elemsMap[name].onclick = () => { selectElem(name); }; - }); - - selectAll(); -} - -document.addEventListener('DOMContentLoaded', (event) => { - main(); -});