From 44859407cf449c2f115a3e3319f8378219fa2efe Mon Sep 17 00:00:00 2001 From: Xiao X <103391432+QXIoa@users.noreply.github.com> Date: Wed, 27 May 2026 19:01:40 -0400 Subject: [PATCH] Sha256 > Main (#1) * Update SHA256Advanced.java ByteFromHex function * OH MY GOD 45 mins of coding. my brain hurts lol. its likely i will move sha256 to its own package inside of hash as Digest and several other classes will be included in it so instead of plopping them inside of misc i think ill use a standalone package. thanks for reading my rant * several sha components finally made sha256 standalone package, added classes: HMAC HKDF (placeholder for now) Hex Digest too but i did that last night * desc maybe it done * Update README.md * COMPLETION! XACrypto\SHA256 is officially finished in its entirety. I might still make more modifications tho lol * Update XACrypto.java yippie! i made a dumb mistake * bug fix TWO. GOD. DAMN. CHARACTERS. completely messed up the end hash. i used 0 instead of i inside a for loop. i want to die :) * remove tests + update README + good riddance garbage messagedigest sha256 yip --- .idea/inspectionProfiles/Project_Default.xml | 16 ++ README.md | 11 +- src/de/caydenno1/xacrypto/XACrypto.java | 2 + src/de/caydenno1/xacrypto/hash/SHA256.java | 25 --- .../xacrypto/hash/SHA256Advanced.java | 75 ------- .../xacrypto/hash/sha256/Digest.java | 97 +++++++++ .../caydenno1/xacrypto/hash/sha256/HKDF.java | 66 ++++++ .../caydenno1/xacrypto/hash/sha256/HMAC.java | 32 +++ .../caydenno1/xacrypto/hash/sha256/Hex.java | 60 ++++++ .../xacrypto/hash/sha256/SHA256.java | 194 ++++++++++++++++++ .../xacrypto/misc/XACryptoException.java | 28 +++ 11 files changed, 504 insertions(+), 102 deletions(-) create mode 100644 .idea/inspectionProfiles/Project_Default.xml delete mode 100644 src/de/caydenno1/xacrypto/hash/SHA256.java delete mode 100644 src/de/caydenno1/xacrypto/hash/SHA256Advanced.java create mode 100644 src/de/caydenno1/xacrypto/hash/sha256/Digest.java create mode 100644 src/de/caydenno1/xacrypto/hash/sha256/HKDF.java create mode 100644 src/de/caydenno1/xacrypto/hash/sha256/HMAC.java create mode 100644 src/de/caydenno1/xacrypto/hash/sha256/Hex.java create mode 100644 src/de/caydenno1/xacrypto/hash/sha256/SHA256.java create mode 100644 src/de/caydenno1/xacrypto/misc/XACryptoException.java diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..17ae7d9 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/README.md b/README.md index 41425dc..4d37675 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,13 @@ To compile on MacOS 26 (may work on other OS, idk): 4. jar cfe XACrypto.jar de.caydenno1.xacrypto.XACrypto -C out . # package the .class files into a .jar 5. (optional)- jar tf XACrypto.jar # view the contents of the jarfile -XACrypto.jar is now in the project root (if u did everything correctly). +To compile on Windows 10: --- A new release will **NOT** be published until SHA256Advanced is complete. -- +1. git clone https://github.com/Geprivilegieerde-Anonimiteit-BV/XACrypto.git && REM download the git repository +2. mkdir out && REM create output directory +3. dir /s /b src\*.java > sources.txt && REM create sources +4. javac -d out @sources.txt && REM form sources into java bytecode +5. jar cfe XACrypto.jar de.caydenno1.xacrypto.XACrypto -C out . && REM form java bytecode into jar +6. (optional)- jar tf XACrypto.jar && view jarfile contents + +XACrypto.jar is now in the project root (if u did everything correctly). diff --git a/src/de/caydenno1/xacrypto/XACrypto.java b/src/de/caydenno1/xacrypto/XACrypto.java index 43e2f10..c8c74f8 100644 --- a/src/de/caydenno1/xacrypto/XACrypto.java +++ b/src/de/caydenno1/xacrypto/XACrypto.java @@ -2,4 +2,6 @@ package de.caydenno1.xacrypto; public class XACrypto { private XACrypto() {} + + static void main(String[] args) {} } diff --git a/src/de/caydenno1/xacrypto/hash/SHA256.java b/src/de/caydenno1/xacrypto/hash/SHA256.java deleted file mode 100644 index 66acb51..0000000 --- a/src/de/caydenno1/xacrypto/hash/SHA256.java +++ /dev/null @@ -1,25 +0,0 @@ -package de.caydenno1.xacrypto.hash; - -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -public class SHA256 { - // THIS IS A TEMPORARY FILE AND EXTREMELY VOLATILE!! it will be removed when i create a more advanced sha256 (i just dont have the time rn so this will be here for now) - // this just uses MessageDigest and is extremely BAD! do not use this, do not use it, dont use itttt! lol // - // you have been warned. // - - private SHA256(){}; - - public static String hash(String raw) throws NoSuchAlgorithmException { - MessageDigest dig = MessageDigest.getInstance("SHA-256"); - - byte[] res = dig.digest(raw.getBytes(StandardCharsets.UTF_8)); - StringBuilder hex = new StringBuilder(); - for (byte b :res) { - hex.append(String.format("%02x", b)); - } - - return hex.toString(); - }; -} diff --git a/src/de/caydenno1/xacrypto/hash/SHA256Advanced.java b/src/de/caydenno1/xacrypto/hash/SHA256Advanced.java deleted file mode 100644 index 2cdb630..0000000 --- a/src/de/caydenno1/xacrypto/hash/SHA256Advanced.java +++ /dev/null @@ -1,75 +0,0 @@ -package de.caydenno1.xacrypto.hash; - -import de.caydenno1.xacrypto.misc.Constants; - -import java.nio.ByteBuffer; - -public final class SHA256Advanced { - private SHA256Advanced() {}; - - private static int ROTR(int x, int n){ - return (x >>> n) | (x << (32 - n)); - } - - static void compress(int[] h, byte[] b, int offline){ - int[] w = new int [64]; - - for (int i =0; i< 16;i++){ - int base = offline + (i<<2); - w[i] = ((b[base]&0xff) << 24) - | ((b[base+1]&0xff) << 16) - | ((b[base+2]&0xff) << 8) - | (b[base+3]&0xff); - } - - for (int i=16;i<64;i++){ - int s0 = ROTR(w[i - 15], 7) ^ ROTR(w[i - 15], 18) ^ (w[i - 15] >>> 3); - int s1 = ROTR(w[i - 2], 17) ^ ROTR(w[i - 2], 19) ^ (w[i - 2] >>> 10); - - w[i] = w[i - 16] + s0 + w[i - 7] + s1; - } - - int Va = h[0], Vb = h[1], Vc = h[2], Vd = h[3]; - int Ve = h[4], Vf = h[5], Vg = h[6], Vh = h[7]; - - for (int i = 0; i<64; i++){ - int S1 = ROTR(Ve, 6)^ROTR(Ve,11)^ROTR(Ve, 25); - int ch = (Ve&Vf)^(~Ve&Vg); - int tv1 = Vh+S1+ch+Constants.SHA256_K[0]+w[0]; - int S0 = ROTR(Va, 2)^ROTR(Va,13)^ROTR(Va,22); - int maj = (Va&Vb)^(Va&Vc)^(Vb&Vc); - int tv2 = S0+maj; - Vh = Vg; Vg = Vf; Vf = Ve; Ve = Vd + tv1; - Vd = Vc; Vc = Vb; Vb = Va; Va = tv1+ tv2; - } - - h[0] += Va; h[1] += Vb; h[2] += Vc; h[3] += Vd; - h[4] += Ve; h[5] += Vf; h[6] += Vg; h[7] += Vh; - } - - static byte[] pad(byte[] data) { - long b = (long) data.length * 8L; - int p = 64 - (int)((data.length + 8) % 64); - if (p<1) p += 64; - - int t = data.length + p + 8; - - byte[] pd = new byte[t]; - System.arraycopy(data, 0, p, 0, data.length); - pd[data.length] = (byte) 0x80; - - for (int i =7; i>=0;i--) { - pd[t - 8 + i] = (byte) (b & 0xff); - b >>>= 8; - } - - return pd; - } - public static String Byte2Hex(byte[] b) { - StringBuilder o = new StringBuilder(b.length * 2); - for (byte bi : b) { - o.append(String.format("%02x",bi&0xff)); - } - return o.toString(); - } -} diff --git a/src/de/caydenno1/xacrypto/hash/sha256/Digest.java b/src/de/caydenno1/xacrypto/hash/sha256/Digest.java new file mode 100644 index 0000000..a4dab68 --- /dev/null +++ b/src/de/caydenno1/xacrypto/hash/sha256/Digest.java @@ -0,0 +1,97 @@ +package de.caydenno1.xacrypto.hash.sha256; + +import de.caydenno1.xacrypto.misc.Constants; +import de.caydenno1.xacrypto.misc.XACryptoException; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +import static de.caydenno1.xacrypto.hash.sha256.SHA256.Word2Byte; +import static de.caydenno1.xacrypto.hash.sha256.SHA256.compress; + +public final class Digest { + private final int[] s = Constants.SHA256_H.clone(); + private final byte[] buf = new byte[64]; + private int bufLen = 0; + private long total = 0L; + + public Digest(){}; + + public Digest upd(byte[] d) throws XACryptoException { + return upd(d, 0, d.length); + } + + /** + * i have never used javadoc before ;-; just using google for javadoc format lol + * @param d data + * @param o Offset + * @param l count + * @return {@code this} end data after modification + */ + public Digest upd(byte[] d, int o, int l) throws XACryptoException { + if(o<0||l<0||o+l>d.length) throw new XACryptoException("take a look at your code :)"); + total += l; + if (bufLen > 0) { + int fil = Math.min(64 - bufLen, l); + System.arraycopy(d,o,buf,bufLen,fil); + bufLen += fil;o+=fil;l-=fil; + if (bufLen == 64) { compress(s, buf, 0); bufLen=0; } + } + + while(l >= 64){ + compress(s,d,o); + o += 64; + l -= 64; + }; + // save whats remaining i suppose.. + if (l>0) { + System.arraycopy(d, o, buf, 0, l); + bufLen = l; + }; + return this; // we returned "this" !1 + } + public Digest upd(String text) throws XACryptoException { return upd(text.getBytes(StandardCharsets.UTF_8) );}; + + public Digest upd(ByteBuffer buf) throws XACryptoException { + if (buf.hasArray()) { return upd(buf.array(), buf.arrayOffset() + buf.position(), buf.remaining()); } + byte[] temp = new byte[buf.remaining()]; + buf.get(temp); + return upd(temp); + }; + + @SuppressWarnings("ConstantValue") + public byte[] digest() { + byte[] t = new byte[bufLen]; + System.arraycopy(buf,0,t,0,bufLen); + long bit = total * 8L; + int pad = 64 - (int)((bufLen+1+8) % 64)%64; + if (pad<0) pad += 64; + int total = bufLen + 1 + pad + 8; + + byte[] last = new byte[total]; + System.arraycopy(t, 0, last, 0, bufLen); + last[bufLen] = (byte) 0x80; + for (int i = 7; i >= 0; i--) { + last[total - 8 + i] = (byte) (bit & 0xff); + bit >>>= 8; + } + + int[] sa = s.clone(); + for (int off = 0; off < last.length; off += 64) { compress(sa, last, off); } + byte[] o = Word2Byte(sa); + reset(); + return o; + } + + public void reset() { + System.arraycopy(Constants.SHA256_H, 0, s, 0, 8); + Arrays.fill(buf, (byte) 0); + bufLen = 0; + total = 0L; + } + + public long get() { + return total; + } +} \ No newline at end of file diff --git a/src/de/caydenno1/xacrypto/hash/sha256/HKDF.java b/src/de/caydenno1/xacrypto/hash/sha256/HKDF.java new file mode 100644 index 0000000..8ba629f --- /dev/null +++ b/src/de/caydenno1/xacrypto/hash/sha256/HKDF.java @@ -0,0 +1,66 @@ +package de.caydenno1.xacrypto.hash.sha256; + +import de.caydenno1.xacrypto.misc.XACryptoException; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +import static de.caydenno1.xacrypto.hash.sha256.HMAC.*; +import static de.caydenno1.xacrypto.hash.sha256.SHA256.*; + +public class HKDF { + private HKDF(){} + + public static byte[] extract(byte[] salt, byte[] ikm) throws XACryptoException { + byte[] effectivity = (salt == null || salt.length == 0) ? new byte[32] : salt; + return hmac(effectivity, ikm); + } + + public static byte[] expand(byte[] prk, byte[] inf, int len) throws XACryptoException { + if (len <= 0 || len > 255 * 64) throw new XACryptoException(new String[]{"prk=" + java.util.Arrays.toString(prk), "inf=" + java.util.Arrays.toString(inf), "len=" + String.valueOf(len)}, (byte) 0); + int n = (len + 32 - 1) / 32; + byte[] okm = new byte[n*32]; + byte[] t = new byte[0]; + + for (int i=1;i<=n;i++){ + byte[] in = new byte[t.length + inf.length + 1]; + System.arraycopy(t, 0, in, 0, t.length); + System.arraycopy(inf, 0, in, t.length, inf.length); + in[t.length+inf.length] = (byte) i; + t = hmac(prk,in); + System.arraycopy(t,0,okm,(i-1) * 32, 32); + } + + return Arrays.copyOf(okm,len); + } + + public static byte[] hkdf(byte[] ikm, byte[] sal, byte[] inf, int len) throws XACryptoException { + byte[] prk = extract(sal, ikm); + return expand(prk, inf, len); + } + + public static byte[] pbkdf2(byte[] pass, byte[] sal, int it, int dk) throws XACryptoException { + if (it<1) throw new XACryptoException("interations too low. given:".concat(" ").concat(String.valueOf(it))); + int blk = (dk + 32 - 1) / 32; + byte[] d = new byte[blk * 32]; + + for (int i = 1; i<=blk; i++) { + byte[] II = { (byte)(i >> 24), (byte)(i >> 16), (byte)(i >> 8), (byte) i }; + byte[] SI = conc(sal, II); + + byte[] u = hmac(pass, SI); + byte[] f = u.clone(); + + for (int j = 1; j 64) ? hash(key) : key; + + byte[] i = new byte[64]; + byte[] o = new byte[64]; + for (int l=0;l<64;l++) { + byte k_ = (l < k.length) ? k[l] : 0; + i[l] = (byte)(k_^0x36); + o[l] = (byte)(k_^0x5c); + } + + byte[] in = new Digest().upd(i).upd(mesg).digest(); + + return new Digest().upd(o).upd(in).digest(); + } + + public static byte[] hmac(String key, String mesg) throws XACryptoException { + return hmac(key.getBytes(StandardCharsets.UTF_8), + mesg.getBytes(StandardCharsets.UTF_8)); + } +} diff --git a/src/de/caydenno1/xacrypto/hash/sha256/Hex.java b/src/de/caydenno1/xacrypto/hash/sha256/Hex.java new file mode 100644 index 0000000..6ae335f --- /dev/null +++ b/src/de/caydenno1/xacrypto/hash/sha256/Hex.java @@ -0,0 +1,60 @@ +package de.caydenno1.xacrypto.hash.sha256; + +import de.caydenno1.xacrypto.misc.XACryptoException; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class Hex { + public static byte[] hash(byte[] data) throws XACryptoException { + return new Digest().upd(data).digest(); + } + + public static byte[] hash(String text) throws XACryptoException { + return hash(text.getBytes(StandardCharsets.UTF_8)); + } + + public static String hashPlain(String text) throws XACryptoException { + byte[] res = new Digest().upd(text).digest(); + StringBuilder builder = new StringBuilder(); + + for (byte b :res) { + builder.append(String.format("%02x", b & 0xFF)); + } + + return builder.toString(); + } + + public static String hashHex(String text) throws XACryptoException { + return Byte2Hex(hash(text)); + } + + public static String hashHex(byte[] data) throws XACryptoException { + return Byte2Hex(hash(data)); + } + + public static ByteBuffer Hash2Buffer(byte[] data) throws XACryptoException { + return ByteBuffer.wrap(hash(data)).asReadOnlyBuffer(); + } + + public static byte[] doubleHash(byte[] data) throws XACryptoException { + return hash(hash(data)); + } + + public static byte[] HashFile(String loc) throws java.io.IOException, XACryptoException { + byte[] bytes = Files.readAllBytes(Paths.get(loc)); + return hash(bytes); + } + + public static String Byte2Hex(byte[] b) { + StringBuilder o = new StringBuilder(b.length * 2); + for (byte bi : b) { + o.append(String.format("%02x",bi&0xff)); + } + return o.toString(); + } + + +} diff --git a/src/de/caydenno1/xacrypto/hash/sha256/SHA256.java b/src/de/caydenno1/xacrypto/hash/sha256/SHA256.java new file mode 100644 index 0000000..5ef8d55 --- /dev/null +++ b/src/de/caydenno1/xacrypto/hash/sha256/SHA256.java @@ -0,0 +1,194 @@ +package de.caydenno1.xacrypto.hash.sha256; + +import de.caydenno1.xacrypto.misc.Constants; +import de.caydenno1.xacrypto.misc.XACryptoException; + +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.RecursiveTask; + +import static de.caydenno1.xacrypto.hash.sha256.Hex.hash; +import static de.caydenno1.xacrypto.hash.sha256.Hex.doubleHash; +public final class SHA256 { + private SHA256(){} + + private static int ROTR(int x, int n){ + return (x >>> n) | (x << (32 - n)); + } + public static void compress(int[] h, byte[] b, int offline){ + int[] w = new int [64]; + + for (int i =0; i< 16;i++){ + int base = offline + (i<<2); + w[i] = ((b[base]&0xff) << 24) + | ((b[base+1]&0xff) << 16) + | ((b[base+2]&0xff) << 8) + | (b[base+3]&0xff); + } + + for (int i=16;i<64;i++){ + int s0 = ROTR(w[i - 15], 7) ^ ROTR(w[i - 15], 18) ^ (w[i - 15] >>> 3); + int s1 = ROTR(w[i - 2], 17) ^ ROTR(w[i - 2], 19) ^ (w[i - 2] >>> 10); + + w[i] = w[i - 16] + s0 + w[i - 7] + s1; + } + + int Va = h[0], Vb = h[1], Vc = h[2], Vd = h[3]; + int Ve = h[4], Vf = h[5], Vg = h[6], Vh = h[7]; + + for (int i = 0; i<64; i++){ + int S1 = ROTR(Ve, 6)^ROTR(Ve,11)^ROTR(Ve, 25); + int ch = (Ve&Vf)^(~Ve&Vg); + int tv1 = Vh+S1+ch+Constants.SHA256_K[i]+w[i]; + int S0 = ROTR(Va, 2)^ROTR(Va,13)^ROTR(Va,22); + int maj = (Va&Vb)^(Va&Vc)^(Vb&Vc); + int tv2 = S0+maj; + Vh = Vg; Vg = Vf; Vf = Ve; Ve = Vd + tv1; + Vd = Vc; Vc = Vb; Vb = Va; Va = tv1+ tv2; + } + + h[0] += Va; h[1] += Vb; h[2] += Vc; h[3] += Vd; + h[4] += Ve; h[5] += Vf; h[6] += Vg; h[7] += Vh; + } + @SuppressWarnings("ConstantValue") + static byte[] pad(byte[] data) { + long b = (long) data.length * 8L; + int p = 64 - (int)((data.length + 8) % 64); + if (p<1) p += 64; + + int t = data.length + p + 8; + + byte[] pd = new byte[t]; + System.arraycopy(data, 0, pd, 0, data.length); + pd[data.length] = (byte) 0x80; + + for (int i =7; i>=0;i--) { + pd[t - 8 + i] = (byte) (b & 0xff); + b >>>= 8; + } + + return pd; + } + + + + public static byte[] Word2Byte(int[] w){ + byte[] o = new byte[w.length * 4]; + for (int i=0;i>> 24); + o[i * 4 + 1] = (byte)(w[i] >>> 16); + o[i * 4 + 2] = (byte)(w[i] >>> 8); + o[i * 4 + 3] = (byte) w[i]; + } + return o; + } + private static byte[] cc(byte[] a, byte[] b){ + byte[] o = new byte[a.length + b.length]; + System.arraycopy(a, 0, o, 0, a.length); + System.arraycopy(b, 0, o, a.length, b.length); + return o; + } + + public static boolean ToM(byte[] a, byte[] b) { + if (a == null || b == null) return a == b; + if (a.length != b.length) return false; + int diff = 0; + for (int i = 0; i < a.length; i++) { + diff |= (a[i] ^ b[i]); + } + return diff == 0; + } + + public static final class HashTask extends RecursiveTask{ + private final java.util.List leaves; + private int from,to; + private final boolean Double; + + HashTask(java.util.List leaves, int from, int to, boolean Double) { + this.leaves = leaves; + this.from = from; + this.to = to; + this.Double = Double; + } + + @Override + protected byte[][] compute() { + int len = this.to-this.from; + if (len <= 128) { + byte[][] res = new byte[len][]; + for (int i=0;i leaves) throws XACryptoException { + if (leaves.isEmpty()) throw new XACryptoException("leaves List is empty!"); + + byte[][] lvl = ForkJoinPool.commonPool().invoke(new HashTask(leaves, 0, leaves.size(), false)); + return mergeUp(lvl, (int)1); + }; + + public static byte[] merkRootDuo(java.util.List leaves) throws XACryptoException { + if (leaves.isEmpty()) throw new XACryptoException("leaves List is empty!"); + + byte[][] lvl = ForkJoinPool.commonPool().invoke(new HashTask(leaves, 0, leaves.size(), false)); + return mergeUp(lvl, (int)2); + }; + + private static byte[] mergeUp(byte[][] lvl, int ext) throws XACryptoException { + while (lvl.length > 1) { + int nx = (lvl.length + 1) / 2; + byte[][] up = new byte[nx][]; + for (int i = 0; i < lvl.length - 1; i += 2) { + up[i / 2] = (ext == 1) + ? hash(conc(lvl[i], lvl[i + 1])) + : doubleHash(conc(lvl[i], lvl[i + 1])); + } + if (lvl.length % 2 == 1) up[nx-1] = lvl[lvl.length - 1]; + } + return lvl[0]; + } + + static byte[] conc(byte[] a, byte[] b) { + byte[] out = new byte[a.length+b.length]; + System.arraycopy(a,0,out,0,a.length); + System.arraycopy(b,0,out,a.length,b.length); + return out; + } + + public static byte[] tagHash(String tag, byte[] dat) throws XACryptoException { + byte[] hasdat = hash(tag.getBytes()); + byte[] load = new byte[hasdat.length * 2 + dat.length]; + System.arraycopy(hasdat, 0, load, 0, hasdat.length); + System.arraycopy(hasdat, 0, load, hasdat.length, hasdat.length); + System.arraycopy(dat, 0, load, hasdat.length * 2, dat.length); + return hash(load); + } + + static void xor(byte[] dest, byte[] src) { + for(int i=0;i