Băm mật khẩu ngầm [đóng]


33

Theo tinh thần của Cuộc thi C Underhanded , tôi đang bắt đầu Cuộc thi Code Underhanded. Mục tiêu của cuộc thi này là đơn giản thực hiện một số mã, trong khi khéo léo che giấu một lỗi bất chính bên trong nó.

Cuộc thi

Bạn là một nốt ruồi bí mật của Nga làm việc trong bộ phận CNTT của một cơ quan gián điệp Mỹ. Sếp người Mỹ của bạn vừa yêu cầu bạn thực hiện thuật toán băm mật khẩu để sử dụng để mã hóa các tin nhắn bí mật.

Sếp của bạn muốn bạn thực hiện chức năng sau:

f: String -> byte[16]

chuyển đổi mật khẩu thành số lượng 16 byte phù hợp để sử dụng làm khóa AES. Sếp của bạn muốn có một chức năng bảo mật, trong ngữ cảnh này có nghĩa là các chuỗi mật khẩu khác nhau sẽ tạo ra các kết quả khác nhau với xác suất áp đảo. Ví dụ, trả về băm md5 của đầu vào sẽ là một cách thực hiện đơn giản f.

Tất nhiên, ông chủ thực sự của bạn trong cơ quan gián điệp Nga sẽ muốn bạn lật đổ quá trình này. Nhiệm vụ của bạn là triển khai fsao cho người Nga có thể giải mã tất cả các tin nhắn bí mật được mã hóa bằng các khóa được trả về f.

Để làm như vậy, bạn phải thực hiện fsao cho nó chỉ trả về một tập hợp con nhỏ trong 2 ^ 128 đầu ra có thể. Cụ thể, bạn fphải trả lại tối đa 2 ^ 16 kết quả khác nhau để người Nga có thể thực hiện tìm kiếm dễ dàng cho khóa chính xác cho mỗi tin nhắn được mã hóa mà họ muốn giải mã.

Tuy nhiên, hãy nhớ rằng gián điệp mang án tử hình. Để không bị bắt, chức năng của bạn fphải tạo ra ít nhất 2 ^ 8 kết quả khác nhau, do đó việc kiểm tra một cách khó hiểu về một vài kết quả đầu ra fkhông có khả năng tiết lộ một bản sao. Và quan trọng nhất, mã bạn giới thiệu để giới hạn phạm vi fphải trông vô tình, không cố ý. Nếu bạn từng bị lôi vào phòng xử án, phải có một số nghi ngờ hợp lý về việc bạn đã đưa ra lỗi cố ý hay vô tình.

Đánh giá

Tôi và hai người khác tôi tuyển dụng sẽ đánh giá các mục (gửi email cho tôi nếu bạn muốn đánh giá). Tôi đang cung cấp 200 tiền thưởng danh tiếng cho mục thắng. Đệ trình phải được tải lên trước ngày 1 tháng 5.

Đánh giá sẽ tính đến các tiêu chí sau:

  • ftuân thủ thông số kỹ thuật không, tức là nó có tạo ra từ 2 ^ 8 đến 2 ^ 16 đầu ra có thể. Đừng cảm thấy đây là những giới hạn cứng, nhưng chúng tôi sẽ trừ điểm nếu bạn ở quá xa phạm vi.
  • Là lỗi có thể là kết quả của một lỗi vô ý?
  • Làm đầu ra của fnhìn ngẫu nhiên?
  • Việc thực hiện của bạn càng ngắn fthì càng tốt.
  • Việc thực hiện của bạn càng rõ ràng fthì càng tốt.

Ghi chú

Bạn có thể sử dụng bất kỳ ngôn ngữ để thực hiện mã của bạn. Bạn đang cố gắng che giấu một lỗi trong tầm nhìn rõ ràng, vì vậy mã bị xáo trộn không được đề xuất.

Bạn có thể muốn xem qua một số người chiến thắng trong cuộc thi Underhanded C trước đây để cảm nhận về những gì làm cho một bài nộp tốt.

Chuỗi đầu vào sẽ có thể in ascii (bao gồm 32 đến 126, bao gồm). Bạn có thể giả sử độ dài tối đa hợp lý nếu bạn muốn.


1
Có bất kỳ hạn chế về chuỗi đầu vào? Giống như nó chỉ bao gồm bảng chữ cái?
Ali1S 232

@Gajet: bạn phải xử lý tất cả các ký tự ascii có thể in được (bao gồm 32 đến 126, bao gồm).
Keith Randall

Là phạm vi đầu ra tất cả các chuỗi 16 byte, hoặc chỉ có thể in được?
gian hàng

@boothby: tất cả các giá trị 16 byte có thể (2 ^ 128 khả năng)
Keith Randall

1
Tôi đang bỏ phiếu để đóng câu hỏi này dưới dạng ngoài chủ đề vì các thử thách ngầm không còn thuộc chủ đề trên trang web này. meta.codegolf.stackexchange.com/a/8326/20469
mèo

Câu trả lời:


15

C

2 ^ 16 đầu ra có thể (hoặc gấp 2 ^ 8 lần số ký tự được sử dụng).
Sử dụng triển khai MD5 của Linux, đó là, AFAIK, tốt. Nhưng điều này cho cùng một hàm băm, ví dụ, cho "40" và "42".
EDIT: Đổi tên bcopyđể memcpy(thông số hoán đổi tất nhiên).
EDIT: Chuyển đổi từ chương trình sang chức năng, để đáp ứng yêu cầu tốt hơn.

#include <string.h>
#include <openssl/md5.h>

void f(const unsigned char *input, unsigned char output[16]) {

    /* Put the input in a 32-byte buffer, padded with zeros. */
    unsigned char workbuf[32] = {0};
    strncpy(workbuf, input, sizeof(workbuf));

    unsigned char res[MD5_DIGEST_LENGTH];
    MD5(workbuf, sizeof(workbuf), res);

    /* NOTE: MD5 has known weaknesses, so using it isn't 100% secure.
     * To compensate, prefix the input buffer with its own MD5, and hash again. */
    memcpy(workbuf+1, workbuf, sizeof(workbuf)-1);
    workbuf[0] = res[0];
    MD5(workbuf, sizeof(workbuf), res);

    /* Copy the result to the output buffer */
    memcpy(output, res, 16);
}

/* Some operating systems don't have memcpy(), so include a simple implementation */
void *
memcpy(void *_dest, const void *_src, size_t n)
{
    const unsigned char *src = _src;
    unsigned char *dest = _dest;
    while (n--) *dest++ = *src++;
    return _dest;
}

Đây có phải là một lỗ hổng với MD5?
Ali1S232

@Gajet, Không, tôi đã sử dụng MD5 của Linux, điều này hoàn toàn ổn (AFAIK).
ugoren

Họ tại sao nó không tạo ra đầu ra nhiều hơn có thể?
Ali1S 232

1
@Gajet: Hãy xem xét những gì xảy ra trong bcopybước này ... đó là một chút sai lầm tốt đẹp, vì bcopychức năng BSD thực tế sẽ hoạt động đúng ở đây.
han

@han, Thật ra, bây giờ tôi thấy rằng tôi bcopycó lỗi. Tôi sẽ thay đổi nó thành memcpy, và sau đó việc thực hiện tương tự sẽ trở nên hợp lệ.
xấu xí

13

C

Đây có thể không phải là mục tham gia cuộc thi hào nhoáng nhất, nhưng tôi nghĩ sau đây là loại hàm băm có thể được tạo bởi bất kỳ lập trình viên nào quá thông minh vì lợi ích của họ, với một ý tưởng mơ hồ về loại hoạt động bạn thấy trong các hàm băm:

#include <stdio.h>
#include <string.h>
#include <stdint.h>

void hash(const char* s, uint8_t* r, size_t n)
{
     uint32_t h = 123456789UL;
     for (size_t i = 0; i < n; i++) {
          for (const char* p = s; *p; p++) {
               h = h * 33 + *p;
          }
          *r++ = (h >> 3) & 0xff;
          h = h ^ 987654321UL;
     }
}

int main()
{
     size_t n = 1024;
     char s[n];
     size_t m = 16;
     uint8_t b[m];
     while (fgets(s, n, stdin)) {
          hash(s, b, m);
          for (size_t i = 0; i < m; ++i)
               printf("%02x", b[i]);
          printf("\n");
     }
}

Trong thực tế, hàm băm có thể trả về không quá L * 2048 kết quả khác nhau, trong đó L là số lượng độ dài chuỗi đầu vào khác nhau có thể xảy ra. Trong thực tế, tôi đã thử nghiệm mã trên 1,85 triệu dòng đầu vào duy nhất từ ​​các trang thủ công và tài liệu html trên máy tính xách tay của tôi và chỉ nhận được 85428 băm khác nhau.


0

Scala:

// smaller values for more easy tests:
val len = 16
// make a 16 bytes fingerprint
def to16Bytes (l: BigInt, pos: Int=len) : List[Byte] = 
  if (pos == 1) List (l.toByte) else (l % 256L).toByte :: to16Bytes (l / 256L, pos-1)
/** if number isn't prime, take next */
def nextProbPrime (l: BigInt) : BigInt = 
  if (l.isProbablePrime (9)) l else nextProbPrime (l + 1)
/** Take every input, shift and add, but take primes */
def codify (s: String): BigInt = 
  (BigInt (17) /: s) ((a, b) => nextProbPrime (a * BigInt (257) + b))
/** very, very short Strings - less than 14 bytes - have to be filled, to obscure them a bit: */
def f (s: String) : Array [Byte] = {
  val filled = (if (s.size < 14) s + "secret" + s else s)
  to16Bytes (codify (filled + filled.reverse)).toArray.map (l => nextProbPrime (l).toByte) 
}

Kiểm tra, nếu kết quả không giống với đầu vào tương tự:

val samples = List ("a", "aa", "b", "", "longer example", "This is a foolish, fishy test") 

samples.map (f) 

 List[Array[Byte]] = List(
Array (-41, -113, -79, 127, 29, 127, 31, 67, -19, 83, -73, -31, -101, -113, 97, -113), 
Array (-19, 7, -43, 89, -97, -113, 47, -53, -113, -127, -31, -113, -67, -23, 127, 127), 
Array (-41, -113, -79, 127, 29, 127, 31, 67, -19, 83, -73, -31, -101, -113, 97, -113), 
Array (37, -19, -7, 67, -83, 89, 59, -11, -23, -47, 97, 83, 19, 2, 2, 2), 
Array (79, 101, -47, -103, 47, -13, 29, -37, -83, -3, -37, 59, 127, 97, -43, -43), 
Array (37, 53, -43, -73, -67, 5, 11, -89, -37, -103, 107, 97, 37, -71, 59, 67))

Lỗi là chỉ sử dụng các số nguyên tố cho mã hóa. Thay vì

scala> math.pow (256, 16)
res5: Double = 3.4028236692093846E38

giá trị, chúng tôi kết thúc với

scala> math.pow (54, 16)
res6: Double = 5.227573613485917E27

vì có 54 số nguyên tố dưới 256.


2
5.22e27 >> 2^16. Không có cách nào để vũ phu mà nhiều khả năng.
Keith Randall

bạn đã quên tên của ngôn ngữ
ajax333221

@ ajax333221: Scala. Tôi đã thêm nó vào đầu.
người dùng không xác định

@KeithRandall: Tôi có thể 'vô tình' chỉ sử dụng Byte dương, điều này sẽ làm giảm khả năng của math.pow (27, 16), nhưng đó vẫn là khoảng 8e22.
người dùng không xác định
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.