将leet-speak转换为明文

时间:2010-07-09 17:48:48

标签: c# passwords

除了我在维基百科上读到的语言之外,我对 L33t 语言并不那么谦逊。

我确实需要在我们的密码强度验证工具中添加字典检查,因为leet-speak只会给密码破解过程增加一些微不足道的开销,我想在检查输入之前删除输入。反对字典。

澄清背后的原因:当需要在其密码中添加符号时,许多用户只需对常用字进行一些非常可预测的leet替换,以满足数字和符号包含要求。因为它是如此可预测,所以仅仅使用原始字典单词就会增加密码的实际复杂性。 \修改

不知道所有规则,尤其是“W”之类的多字符替换,并且确定这是一个已被多次解决的问题,包括开源项目。

我正在寻找代码示例,但还没找到任何代码示例。如果它是 C#代码,那将是一个奖励!,但任何通用语言的代码都会有所帮助。

另外,有一种可扩展的方法会很好,因为据我所知,这种方言很快就会发展。能够在一年内添加一些规则,这将是很好的。

不,这不是我整个密码强度检查的基础。这只是我在这篇文章中寻求帮助的部分。因此,我们不会被密码和安全问题的其他元素分心,让我描述一下与leet-speak无关的密码问题:

我们使用NIST special publication 800-63来测量密码中的熵位,并且需要策略可配置的等效度量(例如56位)才能使密码有效。这仍然为词典单词提供了空间,这些单词已被简单地提出来,并且从熵的角度来看并不是更好的普通字典单词。

我只想告诉用户“P @ s5w0rd”太靠近字典单词,他们可能会找到更强的密码。

我知道安全考虑因素还有很多,例如人类可以记住的密码与安全密码之间的平衡。这不是那个问题。

所有我要问的是将l33t转换为明文,这应该像代码高尔夫一样有趣和有趣。有没有人见过任何代码示例?

5 个答案:

答案 0 :(得分:13)

我必须说我认为这是一个坏主意...如果你想让它们变得强大,那就提出更好的要求..必须至少8个字符,包含大写和小写字母,至少包含一个数字,和至少一个特殊的角色。在禁用帐户之前实施最大授权失败计数器。一旦完成,你还担心什么?

答案 1 :(得分:10)

还提供一些代码:

String password  = @"\/\/4573Fu|_";
Dictionary<string, string> leetRules = new Dictionary<string, string>();

leetRules.Add("4", "A");
leetRules.Add(@"/\", "A");
leetRules.Add("@", "A");
leetRules.Add("^", "A");

leetRules.Add("13", "B");
leetRules.Add("/3", "B");
leetRules.Add("|3", "B");
leetRules.Add("8", "B");

leetRules.Add("><", "X");

leetRules.Add("<", "C");
leetRules.Add("(", "C");

leetRules.Add("|)", "D");
leetRules.Add("|>", "D");

leetRules.Add("3", "E");

leetRules.Add("6", "G");

leetRules.Add("/-/", "H");
leetRules.Add("[-]", "H");
leetRules.Add("]-[", "H");

leetRules.Add("!", "I");

leetRules.Add("|_", "L");

leetRules.Add("_/", "J");
leetRules.Add("_|", "J");

leetRules.Add("1", "L");

leetRules.Add("0", "O");

leetRules.Add("5", "S");

leetRules.Add("7", "T");

leetRules.Add(@"\/\/", "W");
leetRules.Add(@"\/", "V");

leetRules.Add("2", "Z");

foreach (KeyValuePair<string,string> x in leetRules)
{
    password = password.Replace(x.Key, x.Value);
}

MessageBox.Show(password.ToUpper());

答案 2 :(得分:3)

我发现这个问题很有趣,所以这里有一个额外的答案作为一个智力练习;由于leet speak不能映射到一个唯一的单词,你必须检查一个leet speak链可能给出的可能的解码值。这里有一些示例代码:

public class LeetSpeakDecoder
{
    private Dictionary<string, IEnumerable<string>> Cache { get; set; }
    private Dictionary<string, string> Rules { get; set; }

    public LeetSpeakDecoder()
    {
        Cache = new Dictionary<string, IEnumerable<string>>();
        Rules = new Dictionary<string,string>();

        Rules.Add("4", "A");
        // add rules here...
    }

    public IEnumerable<string> Decode(string leet)
    {
        var list = new List<string>();
        if (Cache.ContainsKey(leet))
        {
            return Cache[leet];
        }

        DecodeOneCharacter(leet, list);
        DecodeMoreThanOneCharacter(leet, list);
        DecodeWholeWord(leet, list);

        list = list.Distinct().ToList();

        Cache.Add(leet, list);
        return list;
    }

    private void DecodeOneCharacter(string leet, List<string> list)
    {
        if (leet.Length == 1)
        {
            list.Add(leet);
        }
    }

    private void DecodeMoreThanOneCharacter(string leet, List<string> list)
    {
        if (leet.Length > 1)
        {   // we split the word in two parts and check how many variations each part will decode to
            for (var splitPoint = 1; splitPoint < leet.Length; splitPoint++)
            {
                foreach (var leftPartDecoded in Decode(leet.Substring(0, splitPoint)))
                {
                    foreach (var rightPartDecoded in Decode(leet.Substring(splitPoint)))
                    {
                        list.Add(leftPartDecoded + rightPartDecoded);
                    }
                }
            }
        }
    }

    private void DecodeWholeWord(string leet, List<string> list)
    {
        if (Rules.ContainsKey(leet))
        {
            list.Add(Rules[leet]);
        }
    }
}

代码认为

  • 一个字符可以保持原样(DecodeOneCharacter
  • 必须通过对单词(DecodeMoreThanOneCharacter
  • 的所有可能分割的解码值的组合来解码单词
  • 必须根据规则(DecodeWholeWord
  • 直接解码

缓存非常有用,因为代码在跟踪哪些排列无用时非常低效:分裂&#34;浪费&#34;进入&#34; w&#34;并且&#34; asteful&#34;或者进入&#34; wa&#34;并且&#34; steful&#34;将导致在右侧重复解码,然后最终在左侧。我没有太多关于它的数据,但它经常被90%以上的解码所击中;对于一个小小的补充,不要太破旧。

由于它返回了所有可能的leet解码字符串的组合,您可能需要查看它的解决方案:例如,Fosco的代码将解码&#34; 137M3P455&#34;到&#34; BTMEPASS&#34;但你可能想知道它也转化为&#34; LETMEPASS&#34; - 这会让你更加畏缩。

答案 3 :(得分:3)

根据上面的samy的回答,这是一个更进一步的增强版本。它允许每个输入字符串有多个输出规则,特别是为从字符串中删除的所有非字母数字字符设置规则。结果是你可以发送Tr0ub4dor&amp; 3的经典XKCD漫画密码并输出Troubador。

我使用它与OP的目的非常相似,以确认提供给我的系统的包含高度安全数据的密码不是基于字典单词。

我正在获取解码函数的输出,并通过字典运行它。

  public class LeetSpeakDecoder
    {
        private Dictionary<string, IEnumerable<string>> Cache { get; set; }
        private Dictionary<string, List<string>> Rules  = new Dictionary<string, List<string>>();

        public void AddRule(string key, string value)
        {
            List<string> keyRules = null;
            if (Rules.ContainsKey(key))
            {
                keyRules = Rules[key];
            }
            else
            {
                keyRules = new List<string>();
                Rules[key] = keyRules;
            }
            keyRules.Add(value);
        }

        public LeetSpeakDecoder()
        {
            Cache = new Dictionary<string, IEnumerable<string>>();


            AddRule("4", "A");
            AddRule("4", "a");
           AddRule(@"/\", "A");
           AddRule("@", "A");
           AddRule("^", "A");
           AddRule("13", "B");
           AddRule("/3", "B");
           AddRule("|3", "B");
           AddRule("8", "B");
           AddRule("><", "X");
           AddRule("<", "C");
           AddRule("(", "C");
           AddRule("|)", "D");
           AddRule("|>", "D");
           AddRule("3", "E");
           AddRule("6", "G");
           AddRule("/-/", "H");
           AddRule("[-]", "H");
           AddRule("]-[", "H");
           AddRule("!", "I");
           AddRule("|_", "L");
           AddRule("_/", "J");
           AddRule("_|", "J");
           AddRule("1", "L");
           AddRule("0", "O");
           AddRule("0", "o");
           AddRule("5", "S");
           AddRule("7", "T");
           AddRule(@"\/\/", "W");
           AddRule(@"\/", "V");
           AddRule("2", "Z");

            const string nonAlpha = @"0123456789!@#$%^&*()-_=+[]{}\|;:'<,>./?""";
            foreach (var currentChar in nonAlpha)
            {
                AddRule(currentChar.ToString(), "");
            }
        }

        public IEnumerable<string> Decode(string leet)
        {
            var list = new List<string>();
            if (Cache.ContainsKey(leet))
            {
                return Cache[leet];
            }

            DecodeOneCharacter(leet, list);
            DecodeMoreThanOneCharacter(leet, list);
            DecodeWholeWord(leet, list);

            list = list.Distinct().ToList();

            Cache.Add(leet, list);
            return list;
        }

        private void DecodeOneCharacter(string leet, List<string> list)
        {
            if (leet.Length == 1)
            {
                list.Add(leet);
            }
        }

        private void DecodeMoreThanOneCharacter(string leet, List<string> list)
        {
            if (leet.Length > 1)
            {   // we split the word in two parts and check how many variations each part will decode to
                for (var splitPoint = 1; splitPoint < leet.Length; splitPoint++)
                {
                    foreach (var leftPartDecoded in Decode(leet.Substring(0, splitPoint)))
                    {
                        foreach (var rightPartDecoded in Decode(leet.Substring(splitPoint)))
                        {
                            list.Add(leftPartDecoded + rightPartDecoded);
                        }
                    }
                }
            }
        }

        private void DecodeWholeWord(string leet, List<string> list)
        {
            if (Rules.ContainsKey(leet))
            {
                foreach (var ruleValue in Rules[leet])
                {
                    list.Add(ruleValue);
                }

            }
        }
    }

这是我的输出

Tr0ub4dor&3
Tr0ub4dor&E
Tr0ub4dor&
Tr0ub4dor3
Tr0ub4dorE
Tr0ub4dor
Tr0ubAdor&3
Tr0ubAdor&E
Tr0ubAdor&
Tr0ubAdor3
Tr0ubAdorE
Tr0ubAdor
Tr0ubador&3
Tr0ubador&E
Tr0ubador&
Tr0ubador3
Tr0ubadorE
Tr0ubador
Tr0ubdor&3
Tr0ubdor&E
Tr0ubdor&
Tr0ubdor3
Tr0ubdorE
Tr0ubdor
TrOub4dor&3
TrOub4dor&E
TrOub4dor&
TrOub4dor3
TrOub4dorE
TrOub4dor
TrOubAdor&3
TrOubAdor&E
TrOubAdor&
TrOubAdor3
TrOubAdorE
TrOubAdor
TrOubador&3
TrOubador&E
TrOubador&
TrOubador3
TrOubadorE
TrOubador
TrOubdor&3
TrOubdor&E
TrOubdor&
TrOubdor3
TrOubdorE
TrOubdor
Troub4dor&3
Troub4dor&E
Troub4dor&
Troub4dor3
Troub4dorE
Troub4dor
TroubAdor&3
TroubAdor&E
TroubAdor&
TroubAdor3
TroubAdorE
TroubAdor
Troubador&3
Troubador&E
Troubador&
Troubador3
TroubadorE
Troubador
Troubdor&3
Troubdor&E
Troubdor&
Troubdor3
TroubdorE
Troubdor
Trub4dor&3
Trub4dor&E
Trub4dor&
Trub4dor3
Trub4dorE
Trub4dor
TrubAdor&3
TrubAdor&E
TrubAdor&
TrubAdor3
TrubAdorE
TrubAdor
Trubador&3
Trubador&E
Trubador&
Trubador3
TrubadorE
Trubador
Trubdor&3
Trubdor&E
Trubdor&
Trubdor3
TrubdorE
Trubdor

答案 4 :(得分:2)

为什么不直接创建一个函数来创建"pronounceable" passwords并要求用户使用它们?似乎工作少得多,安全性也更好。