加密字符串以匹配原始字符串的长度

时间:2015-04-19 14:10:52

标签: c# string encryption

我需要一个简单的c#算法,该算法需要一串x个字符并加密'它到另一个x字符串。它不必是安全的,但是通过简单地查看加密的字符串来重建原始字符串是不可能的。例如,如果我输入" hello",我应该得到类似" x = w3q"的东西。它不应该简单地将每个角色映射到其他角色,但它并不比这复杂得多。它需要是对称的,所以我需要能够构建"你好"来自" x = w3q"。

到目前为止,我已尝试过RijndaelManaged和RSA加密,但加密后的字符串比原始字符串要长很多。

有什么想法吗?

4 个答案:

答案 0 :(得分:4)

您可以使用ROT13算法开始,然后根据前一个字符更改偏移量。

示例:“你好”

'h'的ROT13 - > 'U'

由于U是字母表中的第21个字母,您接下来将使用ROT21:

'e'的ROT8 - > 'z'

等等。

这样不仅可以保持长度不变,还可以处理额外的字符,只要将它们添加到字母表即可。

如果现在还不够清楚,我道歉,我正在打电话。

修改

这是一些代码,这将更有意义:

    static String alphabet = "abcdefghijklmnopqrstuvwxyz";

public static String encrypt(String originalString)
{
    String returnString = "";
    int shift = alphabet.Length / 2; 

    foreach (char c in originalString)
    {
         int nextIndex = alphabet.IndexOf(c) + shift;

         if (nextIndex > alphabet.Length)
            nextIndex = nextIndex - alphabet.Length;

         returnString += alphabet[nextIndex];
         shift = alphabet.IndexOf(alphabet[nextIndex]);
    }

    return returnString;
}

public static String decrypt(String encryptedString)
{        
    String returnString = "";
    int shift = alphabet.Length / 2; 

    foreach (char c in encryptedString)
    {
        int nextIndex = alphabet.IndexOf(c) - shift;

         if (nextIndex < 0)
            nextIndex = alphabet.Length + nextIndex; // nextIndex is negative so we are decreasing regardless

        returnString += alphabet[nextIndex];
        shift = alphabet.IndexOf(c);
    }

    return returnString;
}

可以根据需要扩展字母表。这不安全,但它很简单,只要看一下就不能轻易破译。

答案 1 :(得分:2)

如果您想要一个众所周知的(经典)密码,这里是Vigenère的实现。

import java.util.EnumSet;
import java.util.Set;

/**
 * Simple object oriented implementation of the classical Vigenère cipher.
 * Note that Vigenère is - of course - not considered secure anymore.
 *
 * @author maartenb
 */

public class Vigenère {
    private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final int LA = ALPHABET.length();

    /**
     * Flags to be used for the Vigenère cipher.
     */
    public enum Flag {
        /**
         * Do not encrypt/decrypt space characters but leave them in the same
         * position.
         */
        SKIP_SPACE;
    }

    private enum State {
        INSTANTIATED, INITIALIZED;
    }

    private enum Operation {
        ENCRYPT, DECRYPT;

        public int direction() {
            switch (this) {
            case ENCRYPT:
                return 1;
            case DECRYPT:
                return -1;
            default:
                throw new IllegalStateException();
            }
        }
    }

    private State state = State.INSTANTIATED;
    private String key;
    private int lk;
    private Set<Flag> flags;

    /**
     * Initializes the cipher with the given key.
     *
     * @param key
     *            the key that can only use the characters in the alphabet
     * @param flags
     *            option flag parameters
     * @throws IllegalArgumentException
     *             if the key contains invalid characters
     */
    public void init(final String key, final Set<Flag> flags) {
        if (key == null || key.isEmpty()) {
            throw new IllegalArgumentException("Key null or empty");
        }

        this.lk = key.length();
        for (int i = 0; i < this.lk; i++) {
            if (ALPHABET.indexOf(key.codePointAt(i)) == -1) {
                throw new IllegalArgumentException("Key character nat index "
                        + i + " not in alphabet");
            }
        }
        this.key = key;
        this.flags = flags;
        this.state = State.INITIALIZED;
    }

    /**
     * Encrypts the plaintext using the key set during initialization.
     *
     * @param plaintext
     *            the plaintext, using the characters in the alphabet
     * @return the ciphertext
     * @throws IllegalStateException
     *             if the cipher wasn't initialized
     * @throws IllegalArgumentException
     *             if the plaintext contains characters not in the alphabet
     */
    public String encrypt(final String plaintext) {
        if (this.state != State.INITIALIZED) {
            throw new IllegalStateException("Not initialized");
        }

        return crypt(plaintext, Operation.ENCRYPT);
    }

    /**
     * Decrypts the ciphertext using the key set during initialization.
     *
     * @param ciphertext
     *            the ciphertext, using the characters in the alphabet
     * @return the plaintext
     * @throws IllegalStateException
     *             if the cipher wasn't initialized
     * @throws IllegalArgumentException
     *             if the ciphertext contains characters not in the alphabet
     */
    public String decrypt(final String ciphertext) {
        if (this.state != State.INITIALIZED) {
            throw new IllegalStateException("Not initialized");
        }

        return crypt(ciphertext, Operation.DECRYPT);
    }

    private String crypt(final String in, final Operation op)
            throws IllegalStateException, IllegalArgumentException {

        final StringBuilder out = new StringBuilder(in.length());

        // legend: c = character, k = key, o = offset, in = input, out = output
        int skipped = 0;
        for (int ino = 0; ino < in.length(); ino++) {
            // get character (code point in Unicode)
            final int inc = in.codePointAt(ino);
            // skip space, if configured
            if (inc == ' ' && this.flags.contains(Flag.SKIP_SPACE)) {
                out.appendCodePoint(' ');
                skipped++;
                continue;
            }
            // get matching key character
            final int kc = this.key.codePointAt(mod(ino - skipped, this.lk));
            final int kco = ALPHABET.indexOf(kc);
            final int inco = ALPHABET.indexOf(inc);
            if (inco == -1) {
                throw new IllegalArgumentException(
                        "Invalid character at offset " + ino);
            }

            // the main calculation
            final int outco = mod(inco + op.direction() * kco, LA);
            final int outc = ALPHABET.codePointAt(outco);
            out.appendCodePoint(outc);
        }
        return out.toString();
    }

    private static int mod(final int x, final int n) {
        // note that % is the remainder operation in Java
        // so it doesn't handle negative values correctly
        return (x % n + n) % n;
    }

    /**
     * Main method for testing purposes only.
     *
     * @param args
     *            ignored
     */
    public static void main(final String[] args) {
        // example taken from Wikipedia page on Vigenère
        final Vigenère vigenere = new Vigenère();
        vigenere.init("LEMON", EnumSet.of(Vigenère.Flag.SKIP_SPACE));
        final String ct = vigenere.encrypt("ATTACK AT DAWN");
        System.out.println(ct);
        final String pt = vigenere.decrypt(ct);
        System.out.println(pt);
    }
}

答案 2 :(得分:1)

您可以根据角色的索引映射到不同的角色,这样就不那么明显了。

private static readonly int[] charOffsets = new[]{30,26,39,...};

private static char EncryptChar(char c, int index)
{
    return (char)(c + charOffests[index % charOffsets.Length]);
}

private static char DecryptChar(char c, int index)
{
    return (char)(c - charOffests[index % charOffsets.Length]);
}

public static string Encrypt(string str)
{
    return new string(str.Select((c, i) => EncryptChar(c, i)));
}

public static string Decrypt(string str)
{
    return new string(str.Select((c, i) => DecryptChar(c, i)));
}

如果你只想要字母字符等,你可以稍微调整它。但是你希望得到这个想法。

答案 3 :(得分:0)

一种选择是使用经典密码,例如Vigenère。如果你准备接受字节而不是可读字符,那么RC4是一种更现代的选择。

Vigenère和RC4都不安全,不适合商业级加密。为此你需要AES。对于相同的输出长度,您可以在CTR模式下尝试AES,但在这种情况下您需要单独发送密钥和随机数。