【问题标题】:Decrypt Hidden Message with bitwise operator使用按位运算符解密隐藏消息
【发布时间】:2017-09-22 04:51:37
【问题描述】:

我遇到了这个练习,它要求你解密下图中加密代码中的隐藏消息。

本练习与按位运算符有关,因此我假设我们需要使用“XOR”运算符来解密具有 00 到 99 范围内的 2 位密钥的代码。

这是我的代码。

char input[9] = "dEsxDI^I" , decrypt[9];      // Variable Declarations and Initializations.
int key;

printf("\n\n\nDecrpytion for the Encrypted code \"dEsxDI^I\"  :\n\n\n");

for(key = 0 ; key <= 99 ; key++) // 00 to 99 Key Testing.
    {
        for (int i = 0; i < 8; i++) // Decryption Process.
            {
                decrypt[i] = input[i] ^ key;
                printf("%c", decrypt[i]);
            }
        printf("    =    Key No (%d)\n\n\n", key); // Displays Key No for each decryption.
    }

printf("\n\n");
return 0;

我解密的消息是“Hi_There”,加密密钥为“44”。 只是想知道这是正确的信息吗?因为这是我解密的所有消息中最合乎逻辑的消息。

没有为此练习提供解决方案,所以我很好奇。 那么,你们的输出是什么?

【问题讨论】:

  • 为什么同一个程序会为不同的人给出不同的答案?
  • 这对于 SO 来说真的不是一个合适的问题。如果您的代码没有问题,您需要什么帮助?
  • 您是在询问在所有可能的解密消息中识别正确消息的算法?还是您只是要求确认唯一可以实际阅读的消息可能是该消息意味着设置该任务的人?
  • 好吧,我只是要求确认从上面的代码中解密的确切消息是什么,因为我对我的解决方案并不十分自信。尽管我解密的消息是我解密的所有消息中唯一可读且有意义的消息。
  • 你们可以尝试解密代码,看看哪些信息是合适的、可读的和有意义的,只是想确认隐藏在代码后面的确切信息是什么。

标签: c encryption bitwise-operators bitwise-xor


【解决方案1】:

我解密的消息是“Hi_There”,加密密钥为“ 44"。只是想知道这是不是正确的信息?

对于 8 字符密码的解决方案是否必须是 8 字符解决方案没有明确的指示,但这是一般情况。如果没有明确的说明(“您的解决方案可能包含,也可能不包含密码中的所有字符。”),我会寻找包含 8 个字符的解决方案。

尽管您没有提供代码的细节,但对所有可能的键进行简单的暴力循环与其他任何方法一样好。由于没有为您提供解决方案,因此您无法在此过程中进行任何比较。您能做的最好的事情是遍历所有密钥,将其应用于密码中的每个字符并输出结果——然后使用您的“好眼力”来挑选解决方案。 (如果您知道解决方案将全部使用大写/小写字符 - 您可以在输出每个结果以供 手动 检查之前进行该检查)。

不清楚您是否被告知XORkey 使用每个字符,或者您是否应该尝试所有合理的按位运算,但一般ORXOR 是一个好地方开始。

XOR 放在一起,您可以执行以下操作:

#include <stdio.h>

int main (void) {

    char *buf = "dEsxDI^I";

    for (int key = 0; key < 100; key++) {   /* loop over all keys */
        char *p = buf;                      /* output key (and char) */
        printf ("key: %2d ('%c')   ", key, key >= ' ' ? key : 0);
        while (*p)                          /* loop over all chars */
            putchar (*p++ ^ key);           /* output decrypted char */
        putchar ('\n');                     /* tidy up with '\n' */
    }

    return 0;
}

使用/输出示例

$ ./bin/keyfind2
key:  0 ('')   dEsxDI^I
key:  1 ('')   eDryEH_H
key:  2 ('')   fGqzFK\K
key:  3 ('')   gFp{GJ]J
key:  4 ('')   `Aw|@MZM
key:  5 ('')   a@v}AL[L
<snip>
key: 12 ('')   hItHERE
<snip>
key: 43 ('+')   OnXSobub
key: 44 (',')   Hi_There
key: 45 ('-')   Ih^Uidsd
<snip>

使用 XOR 应用到密钥并使用手动眼球扫描解决方案,key: 12 ('') hItHERE 看起来很有希望,但它只是一个 7 字符的解决方案,继续 key: 44 (',') Hi_There 提供了一个8 字符的解决方案,并且会是两个答案中更好的一个。

所以,“是的”,我认为您找到了正确的解决方案。


不使用字符串索引的指针

由于使用指针p 来遍历buf 中的密码字符串似乎让您摸不着头脑(别担心,随着时间的推移,它会全部消失),您可以轻松做到字符串索引也是如此。 for 循环与索引一样容易使用。消除指针并使用字符串索引,您可以执行以下操作:

#include <stdio.h>

int main (void) {

    char *buf = "dEsxDI^I";

    for (int key = 0; key < 100; key++) {   /* loop over all keys */
        printf ("key: %2d ('%c')   ", key, key >= ' ' ? key : 0);
        for (int i = 0; buf[i]; i++)        /* loop over all chars */
            putchar (buf[i] ^ key);         /* output decrypted char */
        putchar ('\n');                     /* tidy up with '\n' */
    }

    return 0;
}

(输出完全一样)

您关于在 printf 语句中使用 三元运算符 的问题对于不熟悉它的人来说是一个很好的问题。三元运算符是if/else 语句的简写,其中表达式的结果基于给定的测试条件。三元运算符本质上是:

condition ? if_true_value : if_false_value

在我的printf 声明中,我只是这样做:

printf ("key: %2d ('%c')   ", key, key >= ' ' ? key : 0);

显然key 的整数值与%2d 转换说明符一起使用,以确保所有key 值都打印两个字符宽(这就是2 的目的字段宽度 说明符。现在我们通过%c来看看我要打印什么字符。

key >= ' ' ? key : 0    // huh?

这很容易。第一个可打印的 ASCII 值是0x20(十六进制)或32十进制,对应于' '空格)字符。请参阅下面的 ASCII 表。那么我的测试条件是什么?如果(key &gt;= ' ') 大于或等于空格。如果是,只打印key 所代表的字符。如果不是,则打印 nul-character (十进制 0 或等效字符 '\0' -- 只需要更多输入)。你也可以这样做:

if (key >= ' ')
    printf ("key: %2d ('%c')   ", key, key);
else
    printf ("key: %2d ('')   ", key);

(只是输入更多:)

ASCII 表

Char  Dec  Oct  Hex | Char  Dec  Oct  Hex | Char  Dec  Oct  Hex | Char Dec  Oct   Hex
-------------------------------------------------------------------------------------
(nul)   0 0000 0x00 | (sp)   32 0040 0x20 | @      64 0100 0x40 | `      96 0140 0x60
(soh)   1 0001 0x01 | !      33 0041 0x21 | A      65 0101 0x41 | a      97 0141 0x61
(stx)   2 0002 0x02 | "      34 0042 0x22 | B      66 0102 0x42 | b      98 0142 0x62
(etx)   3 0003 0x03 | #      35 0043 0x23 | C      67 0103 0x43 | c      99 0143 0x63
(eot)   4 0004 0x04 | $      36 0044 0x24 | D      68 0104 0x44 | d     100 0144 0x64
(enq)   5 0005 0x05 | %      37 0045 0x25 | E      69 0105 0x45 | e     101 0145 0x65
(ack)   6 0006 0x06 | &      38 0046 0x26 | F      70 0106 0x46 | f     102 0146 0x66
(bel)   7 0007 0x07 | '      39 0047 0x27 | G      71 0107 0x47 | g     103 0147 0x67
(bs)    8 0010 0x08 | (      40 0050 0x28 | H      72 0110 0x48 | h     104 0150 0x68
(ht)    9 0011 0x09 | )      41 0051 0x29 | I      73 0111 0x49 | i     105 0151 0x69
(nl)   10 0012 0x0a | *      42 0052 0x2a | J      74 0112 0x4a | j     106 0152 0x6a
(vt)   11 0013 0x0b | +      43 0053 0x2b | K      75 0113 0x4b | k     107 0153 0x6b
(np)   12 0014 0x0c | ,      44 0054 0x2c | L      76 0114 0x4c | l     108 0154 0x6c
(cr)   13 0015 0x0d | -      45 0055 0x2d | M      77 0115 0x4d | m     109 0155 0x6d
(so)   14 0016 0x0e | .      46 0056 0x2e | N      78 0116 0x4e | n     110 0156 0x6e
(si)   15 0017 0x0f | /      47 0057 0x2f | O      79 0117 0x4f | o     111 0157 0x6f
(dle)  16 0020 0x10 | 0      48 0060 0x30 | P      80 0120 0x50 | p     112 0160 0x70
(dc1)  17 0021 0x11 | 1      49 0061 0x31 | Q      81 0121 0x51 | q     113 0161 0x71
(dc2)  18 0022 0x12 | 2      50 0062 0x32 | R      82 0122 0x52 | r     114 0162 0x72
(dc3)  19 0023 0x13 | 3      51 0063 0x33 | S      83 0123 0x53 | s     115 0163 0x73
(dc4)  20 0024 0x14 | 4      52 0064 0x34 | T      84 0124 0x54 | t     116 0164 0x74
(nak)  21 0025 0x15 | 5      53 0065 0x35 | U      85 0125 0x55 | u     117 0165 0x75
(syn)  22 0026 0x16 | 6      54 0066 0x36 | V      86 0126 0x56 | v     118 0166 0x76
(etb)  23 0027 0x17 | 7      55 0067 0x37 | W      87 0127 0x57 | w     119 0167 0x77
(can)  24 0030 0x18 | 8      56 0070 0x38 | X      88 0130 0x58 | x     120 0170 0x78
(em)   25 0031 0x19 | 9      57 0071 0x39 | Y      89 0131 0x59 | y     121 0171 0x79
(sub)  26 0032 0x1a | :      58 0072 0x3a | Z      90 0132 0x5a | z     122 0172 0x7a
(esc)  27 0033 0x1b | ;      59 0073 0x3b | [      91 0133 0x5b | {     123 0173 0x7b
(fs)   28 0034 0x1c | <      60 0074 0x3c | \      92 0134 0x5c | |     124 0174 0x7c
(gs)   29 0035 0x1d | =      61 0075 0x3d | ]      93 0135 0x5d | }     125 0175 0x7d
(rs)   30 0036 0x1e | >      62 0076 0x3e | ^      94 0136 0x5e | ~     126 0176 0x7e
(us)   31 0037 0x1f | ?      63 0077 0x3f | _      95 0137 0x5f | (del) 127 0177 0x7f

【讨论】:

  • 感谢您的回复和解决方案。我很感激。我假设您在解决方案中使用了“指针”,因为我还没有了解它。但是如果你不介意解释这行代码的作用 printf ("key: %2d ('%c') ", key, key >= ' ' ? key : 0);为什么需要打印键的字符?这和指针有关吗?
  • "" printf ("key: %2d ('%c') ", key, key >= ' ' ? key : 0); "" ,抱歉没有正确格式化代码。我还是该网站的新手,并试图掌握这些格式。
  • 对不起现金。您可以使用指针或字符串索引来访问每个单独的字符。这是一个选择问题。我只是使用指针p 指向buf 的开头,每次我尝试key 并简单地执行while (*p)(这只是p 指向的字符)然后putchar (*p++ ^ key);(它只是将p 指向的字符与key 进行异或,作为++ 的副作用,p 将指向下一个字符以用于下一个while (*p) 测试:) key &gt;= ' ' ? key : 0只需测试 key 的 ASCII 值是否为 space 或更好(可打印),否则为零。
  • 当您使用指针遍历字符串并到达末尾的nul-terminating 字符*pp 指向的字符是0 导致循环退出)。你可以用for (int i = 0; buf[i]; i++) putchar (buf[i] ^ key); 做同样的事情并完全摆脱指针。 (当你到达nul-terminating 字符buf[i] 为零并且循环退出:)
  • 非常感谢您的澄清。我很感激!
【解决方案2】:

我对您解密的消息进行了 XOR、~XOR、AND、NAND、OR、NOR、左移、右移操作。

我们任何人都会认为答案的关键是44

我没有从该字符串中获得任何其他可读消息。

虽然如果你考虑所有的可能性:

异或:

  1. 键 12:hItHERE
  2. 键 44:Hi_There
  3. 键 112:49.9____

用空格替换下划线(不是不可打印的字符,只是空格)

或者:

  1. 键 14:no~no~o
  2. 键 46:no~no~o

是的,它们都是相同的,实际上 OR 会产生很多带有重复字符的字符串,例如 '{{{{{{{{'

~异或:

  1. 键 243:hItHERE
  2. 键 211:Hi_There

现在可读消息的定义取决于每个人。

hItHERE 可能是空袭的标志。

no~no~o 可能是寻求帮助或拒绝某事。

49.9 可能是生物武器实验室中某种秘密成分的数量。

0~99 是一个相当有限的范围。

【讨论】:

    【解决方案3】:

    目标应该是自动化检测机制。与其从详尽的列表中找到解密的短语,不如编写代码。

    对 OP 的代码稍作修改,下面调用各种valid() 来评估解密的有效性。

    建议 OP 进一步调整 valid() 直到它提供 1 个“最佳”解密。那么解密的“公式”就找到了。


    为了好玩:尝试查找此间谍的电话号码并通过 Google 确定姓名。她的加密数据是"0&gt;?%=;81"。相应地调整valid()


    #include <stdio.h>
    
    #if 1
    int valid(const char *decrypt) {
      size_t end = strspn(decrypt, " ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz");
      return end == 8;
    }
    
    #else
    int valid(const char *decrypt) {
      size_t end = strspn(decrypt, " ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz");
      if (end != 8) return 0;
      for (int i=1; i<8; i++) {
        if (isupper(decrypt[i-1]) && isupper(decrypt[i])) { //reject paired capital letters
          return 0;
        }
      }
      return 1;
    }
    #endif
    
    int main(void) {
      const char input[9] = "dEsxDI^I";
      printf("Decryption for the Encrypted code \"dEsxDI^I\"  :\n\n");
    
      for (int key = 0; key <= 99; key++) {
        char decrypt[9] = ""; // Variable Declarations and Initializations.
        for (int i = 0; i < 8; i++) {
          decrypt[i] = (char) (input[i] ^ key);
        }
        if (valid(decrypt)) {
          printf("Key No %2d Decrypt:<%s>\n", key, decrypt);
        }
      }
      return 0;
    }
    

    输出 - 第一个 valid()

    Decryption for the Encrypted code "dEsxDI^I"  :
    
    Key No  1 Decrypt:<eDryEH_H>
    Key No 10 Decrypt:<nOyrNCTC>
    Key No 11 Decrypt:<oNxsOBUB>
    Key No 16 Decrypt:<tUchTYNY>
    Key No 17 Decrypt:<uTbiUXOX>
    Key No 22 Decrypt:<rSenR_H_>
    Key No 28 Decrypt:<xYodXUBU>
    Key No 29 Decrypt:<yXneYTCT>
    Key No 39 Decrypt:<CbT_cnyn>
    Key No 42 Decrypt:<NoYRnctc>
    Key No 43 Decrypt:<OnXSobub>
    Key No 44 Decrypt:<Hi_There>
    Key No 48 Decrypt:<TuCHtyny>
    Key No 49 Decrypt:<UtBIuxox>
    Key No 60 Decrypt:<XyODxubu>
    Key No 61 Decrypt:<YxNEytct>
    

    输出 - 第二个valid()

    Decryption for the Encrypted code "dEsxDI^I"  :
    
    Key No 22 Decrypt:<rSenR_H_>
    Key No 39 Decrypt:<CbT_cnyn>
    Key No 44 Decrypt:<Hi_There>
    

    【讨论】:

      猜你喜欢
      • 2012-08-15
      • 2013-10-06
      • 2011-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-19
      • 2014-03-06
      相关资源
      最近更新 更多