I made a custom encryption library/class which allows to en-/decrypt Strings with a custom charset. I think you'll get what I mean with that when you take a look at the code.Since I haven't much cryptography knowledge, I'd like to ask if someone who knows about it could tell me if this is safe. I know nothing is 100% safe, but I'd like to know how far it is safe and maybe some improvements.I currently have two programs on a server running, which are trying to brute-force it. After nearly 2 months now, there is nothing found yet, so I guess it's working at least a bit.PreCrypt.javapackage net.prefixaut.prelib.crypt;import java.security.SecureRandom;import java.util.List;import java.util.ArrayList;import java.math.BigInteger;public class PreCrypt {    // Remove Constructor    private PreCrypt() {}    /**     * Default Charset which contains only default Characters.<br/>     * Supports: a-z, A-Z, 0-9 and most special-characters. <b>Current amount of supported Characters: 92</b>     */    public static final String defaultCharset = abcdefghijklmopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ#?!\\$%&/{[(=+-~*_.:,;@<>|)]};    /**     * Complete Charset which contains most relevant Characters<br/>     * <b>Current amount of supported Characters: 102</b>     */    public static final String completeCharset = defaultCharset + \n\t\r + // Extra Space Chars            ; // German Extra Chars    public static char countUp(char c, int amount) {        return PreCrypt.countUp(c, amount, defaultCharset);    }    public static char countUp(char c, int amount, String str) {        return PreCrypt.countUp(c, amount, str.toCharArray());    }    public static char countUp(char c, int amount, char[] charset) {        boolean set = false;        for (int i = 0; i < amount; i++) {            for (int o = 0; o < charset.length; o++) {                if (c == charset[o]) {                    if (o + 1 >= charset.length) o = 0;                    else o++;                    c = charset[o];                    set = true;                    break;                }            }            if (!set) c++;            else set = false;        }        return c;    }    public static char countDown(char c, int amount) {        return PreCrypt.countDown(c, amount, defaultCharset);    }    public static char countDown(char c, int amount, String str) {        return PreCrypt.countDown(c, amount, str.toCharArray());    }    public static char countDown(char c, int amount, char[] charset) {        boolean set = false;        for (int i = 0; i < amount; i++) {            for (int o = 0; o < charset.length; o++) {                if (c == charset[o]) {                    if (o - 1 < 0) o = charset.length - 1;                    else o--;                    c = charset[o];                    set = true;                    break;                }            }            if (!set) c--;            else set = false;        }        return c;    }    public static String encrypt(String code, String key) {        return PreCrypt.encrypt(code, key, PreCrypt.defaultCharset);    }    public static String encrypt(String code, String key, String charset) {        return PreCrypt.encrypt(code, key, charset.toCharArray());    }    public static String encrypt(String code, String key, char[] charset) {        String r = ;        r = PreCrypt.count(code, key, charset, (boolean foo, int number, char c) -> {            if (foo) c = PreCrypt.countUp(c, number, charset);                else c = PreCrypt.countDown(c, number, charset);                return c;            });        return r;    }    public static String decrypt(String code, String key) {        return PreCrypt.decrypt(code, key, PreCrypt.defaultCharset);    }    public static String decrypt(String code, String key, String charset) {        return PreCrypt.decrypt(code, key, charset.toCharArray());    }    public static String decrypt(String code, String key, char[] charset) {        String r = ;        r = PreCrypt.count(code, key, charset, (boolean foo, int number, char c) -> {            if (foo) c = PreCrypt.countDown(c, number, charset);                else c = PreCrypt.countUp(c, number, charset);                return c;            });        return r;    }    @FunctionalInterface    private interface Handler {        public char onCode(boolean foo, int number, char c);    }    private static String count(String code, String key, char[] charset, Handler handler) {        String r = ;        List<Integer> keys = new ArrayList<Integer>();        BigInteger keySum = new BigInteger(new byte[] { 0 });        // Load all Key-Values into KEYS, and summarize them in KEYSUM        for (int i = 0; i < key.length(); i++) {            int v = (int) key.charAt(i);            keys.add(v);            keySum = keySum.add(new BigInteger( + v));        }        List<Integer> temp = new ArrayList<Integer>();        for (int i = 0; i < code.length(); i++) {            char c = code.charAt(i);            int kIndex = i;            // Get current Index            while (kIndex > keys.size() - 1)                kIndex -= keys.size() - 1;            // Load from Index till end, and from 0 till Index into TEMP            for (int o = kIndex; o < keys.size(); o++)                temp.add(keys.get(o));            for (int o = 0; o < kIndex; o++)                temp.add(keys.get(o));            // Encode            for (int o = 0; o < temp.size(); o++) {                int count = (temp.get(o) * (o + 1)) / (keySum.intValue() / key.length()) + keySum.intValue();                count = count >> o + 1;                c = handler.onCode( (temp.get(o) * (o + 1)) % 2 == 0, count, c);            }            r += c;            temp.clear();        }        return r;    }    /**     * Generates a Random String with the length of length, from the {@link PreCrypt#defaultCharset default-Charset}     *      * @param length     *            Length of the random String     */    public static String generateRandomString(int length) {        return PreCrypt.generateRandomString(length, PreCrypt.defaultCharset);    }    /**     * Generates a Random String with the length of the given length, from the given charset     *      * @param length     *            Length of the random String     * @param charset     *            Charset which contains all Characters which are allowed for the random String     */    public static String generateRandomString(int length, CharSequence charset) {        return PreCrypt.generateRandomString(length, (String) charset);    }    /**     * Generates a Random String with the length of the given length, from the given charset     *      * @param length     *            Length of the random String     * @param charset     *            Charset which contains all Characters which are allowed for the random String     */    public static String generateRandomString(int length, String charset) {        return PreCrypt.generateRandomString(length, charset.toCharArray());    }    /**     * Generates a Random String with the length of the given length, from the given charset     *      * @param length     *            Length of the random String     * @param charset     *            Charset which contains all Characters which are allowed for the random String     */    public static String generateRandomString(int length, char[] charset) {        String re = ;        SecureRandom r = new SecureRandom();        for (int i = 0; i < length; i++)            re += charset[ (r.nextInt(charset.length))];        return re;    }}
Custom encryption
java;cryptography
I don't think I can give you a very good answer, but here goes:If the span of (temp.get(o) * (o + 1)) (for use in the evenenss test) is not itself even, then your cyphertext is going to be biased. In other words, if the total span of numbers covered by that function is { 0, 1, 2, ... 7, 8}, Then, { 0, 2, 4, 6, 8 } will output 0, and { 1, 3, 5, 7 } will output 1. notice that there is one less member in the one-output camp than there is in the zero output camp. This means that, when encrypting, there will be more countUp's than countDown's, which is a statistical weakness. How is SecureRandom being used?In the main loop of the count function, I see no usage of the result variable or any kind of persistent state. If you're not carrying state between rounds of the main loop, then your cypher is operating in electronic codebook mode, which is not a good thing. How are you chaining your rounds?Even if you address my concerns, I'm no cryptologist, so I would be very surprised if we can come up with a robust crypto system on this forum. I would strongly encourage you to look into one of the many libraries that provide the AES or a modern stream cypher like Spritz or HC-128 if performance is a constraint. 