개발자 도구 · SHA 해시 계산기
같은 텍스트, 다른 SHA-256: 줄 바꿈, 인코딩 및 숨겨진 바이트
· 작동 방식
샤-256 인코딩 텍스트 처리 중 디버깅
명령줄은 동일한 텍스트처럼 보이는 것에 대해 한 가지를 말하고 브라우저는 다른 것을 말합니다. 후행 줄 바꿈, UTF-16 및 CRLF는 거의 모든 경우를 설명합니다. 이 게시물은 숨겨진 바이트를 찾는 방법을 보여줍니다.
echo는 하나의 해시를 말하고 도구는 다른 해시를 말합니다. 일상적인 불일치와 둘 다 틀린 이유
터미널은 하나의 SHA-256 다이제스트를 보고하고 브라우저는 동일한 텍스트로 보이는 다른 다이제스트를 보고합니다. 명령줄 도구는 손상되지 않았으며 브라우저도 손상되지 않았습니다. 보이는 문자가 동일해 보이더라도 해시되는 바이트는 동일하지 않습니다. 이 게시물에서는 숨겨진 바이트의 가장 일반적인 소스를 추적하고 텍스트 필드와 16진수 뷰어를 사용하여 이를 찾는 방법을 보여줍니다.
문제는 SHA-256 알고리즘 자체에는 거의 없습니다. SHA-256은 결정적입니다. 동일한 바이트는 항상 동일한 다이제스트를 생성하며 다이제스트는 정확합니다. 출력이 다르면 바이트도 달라집니다. "동일한 텍스트"가 모호하기 때문에 혼란이 발생합니다. 사람은 문자를 볼 수 있지만 해시 함수는 바이트를 볼 수 있으며, 둘 사이의 번역에는 숨겨진 차이점이 숨어 있습니다.
후행 줄 바꿈 — echo가 바이트를 추가하고 printf는 추가하지 않는 방식과 이것이 다이제스트에 미치는 영향
쉘의 echo 명령은 출력에 개행 문자(U+000A, 바이트 0x0A)를 추가합니다. 이것은 의도적으로 설계된 것입니다. 텍스트 파일이 줄바꿈으로 끝나는 Unix의 규칙은 echo에게 하나의 간단한 작업을 제공합니다. echo abc를 터미널에 입력하고 이를 sha256sum으로 파이프하면 다이제스트된 바이트는 61 62 63가 아니라 61 62 63 0A(a, b, c의 ASCII 코드 및 줄 바꿈용 바이트)입니다. ToolAcre가 해시를 계산하는 데 사용하는 도구는 61 62 63 바이트를 해시하고 다른 결과를 생성합니다.
printf 명령은 형식 문자열에 개행을 쓰지 않으면 개행을 추가하지 않습니다. printf ABC | sha256sum은 브라우저 도구와 일치하는 61 62 63 바이트의 다이제스트만 계산합니다. 그렇기 때문에 해시를 비교한다는 것은 종종 echo 대신 printf를 실행하거나 -z 플래그를 사용하여 sha256sum에 파이프하거나 도구가 제공하는 모든 형식으로 원시 입력을 지정하는 것을 의미합니다. 숨겨진 줄 바꿈은 브라우저 도구와 명령줄 도구가 일치하지 않는 가장 일반적인 이유입니다.
UTF-8 대 UTF-16 — 일부 쉘 및 편집기에서 동일한 문자가 다른 바이트인 이유
UTF-8 및 UTF-16은 동일한 문자를 다른 바이트 시퀀스로 인코딩합니다. 문자 é(U+00E9, 급성 악센트가 있는 e)는 2개의 UTF-8 바이트(0xC3 0xA9)로 인코딩됩니다. JavaScript가 내부적으로 문자열을 나타내는 방식인 UTF-16에서는 동일한 문자가 다른 순서(엔디안에 따라 다름)로 2바이트를 차지하거나 기본 문자와 결합 표시로 구성된 경우 완전히 다른 형식을 차지합니다. Windows 애플리케이션에서 Café를 복사하여 브라우저 해시 도구에 붙여넣으면 도구 해시 바이트가 Mac 터미널 해시와 일치하지 않을 수 있습니다. 시스템이 기본적으로 다른 인코딩 또는 정규화 형식으로 설정되어 있기 때문입니다.
ToolAcre 해시 도구는 TextEncoder를 통해 해싱하기 전에 텍스트를 명시적으로 UTF-8로 변환합니다. 이는 Unix 명령줄에서 기본적으로 사용하는 인코딩과 동일합니다. apps/dev/src/lib/base64.js의 소스 코드는 UTF-8를 보장하는 new TextEncoder().encode()를 호출하는 textToBytes 함수를 보여줍니다. 다른 시스템이 UTF-16, Latin-1 또는 기타 인코딩을 사용하는 경우 생성되는 바이트는 달라집니다. 이 도구는 다이제스트와 함께 바이트 수를 표시하므로 카페를 붙여넣고 명령줄 해시와 비교하면 인코딩이 다를 경우 다른 바이트 수가 표시됩니다.
CRLF, BOM 및 정규화 - 줄 끝, 바이트 순서 표시 및 보이지 않는 입력 차이로 구성된 악센트와 분해된 악센트
CRLF(캐리지 리턴 + 줄 바꿈, 바이트 0x0D 0x0A)는 Windows의 줄 끝 규칙입니다. LF(라인 피드 단독, 바이트 0x0A)는 Unix 규칙입니다. 텍스트 편집기에서 열었을 때 동일해 보이는 텍스트 파일은 다른 줄 끝을 가질 수 있으며 해당 바이트는 해시 입력의 일부입니다. Windows에서 편집되고 Unix 시스템에서 계산된 SHA-256에 대해 검사된 파일은 한 시스템이 줄 끝을 변환하고 다른 시스템은 변환하지 않은 경우 일치하지 않습니다.
바이트 순서 표시(BOM, UTF-8에 대한 바이트 0xEF 0xBB 0xBF)는 인코딩 신호를 보내는 파일 시작 부분의 선택적 시퀀스입니다. 일부 편집자는 이를 추가합니다. 일부 도구는 이를 제거합니다. 일부는 그것을 무시합니다. 파일에 BOM이 있고 이를 바이트 단위로 해시하는 경우 BOM 바이트는 다이제스트의 일부입니다. 그런 다음 뷰어가 BOM을 숨기는 표시되는 텍스트를 BOM을 추가하지 않는 도구에 복사하면 다이제스트가 일치하지 않습니다. 텍스트 정규화 형식(구성 및 분해된 악센트에 대한 NFD 대 NFC)은 또 다른 레이어를 추가합니다. 동일한 악센트 문자는 사전 구성된 단일 문자로 표시되거나 기본 문자 뒤에 결합 악센트가 오는 것으로 표시될 수 있으며 바이트 시퀀스는 다릅니다.
작업된 예 — 개행 문자 유무에 관계없이 해시된 하나의 문자열, 그리고 두 개의 인코딩으로 각 바이트 차이가 표시됩니다.
진단 방법 1: 16진수 덤프 도구나 온라인 변환기를 사용하여 도구가 작동 중인 바이트를 정확히 확인합니다. 텍스트를 base64 인코더에 붙여넣고 인코딩하면 바이트의 텍스트 레코드가 생성됩니다. 그런 다음 명령줄에서 base64 -d를 사용하여 base64를 디코딩하고 od -A x -t x1z로 파이프하여 16진수 바이트 시퀀스를 확인합니다. 바이트가 일치하면 알고리즘이 올바른 것입니다. 그렇지 않으면 차이가 드러납니다.
진단 방법 2: ToolAcre SHA 해시 계산기를 사용하여 단일 문자로 시작하여 점점 더 긴 입력을 해시합니다. 줄 바꿈(텍스트 상자 안에 Enter를 입력하는 것을 의미)을 추가하고, 공백을 추가하고, 입력이 ASCII가 아닌 소스에서 나온 경우 UTF-16 이스케이프 시퀀스를 사용하여 동일한 텍스트를 추가합니다. 추가할 때마다 다이제스트 변경 사항을 확인하세요. 다이제스트 옆에 표시되는 바이트 수는 도구가 해싱하는 바이트 수를 알려주므로 검색 범위가 크게 좁아집니다.
출력의 16진수 대소문자와 공백 — 순전히 외관상 차이점
다이제스트의 16진수 표현은 대소문자를 구분하지 않습니다. 대문자와 소문자는 모두 동일한 바이트를 나타냅니다(A = 10, a = 10). 일부 도구는 대문자, 일부는 소문자를 표시하고 일부는 둘 중 하나를 허용합니다. 한 다이제스트가 소문자이고 다른 다이제스트가 대문자이면 동일한 다이제스트입니다. 다이제스트 디스플레이의 공백은 순전히 외관상입니다. ba78 16bf와 ba7816bf로 표시되는 다이제스트는 동일합니다. 공간은 단지 형식 선택일 뿐입니다. 대소문자 또는 공백으로 인한 불일치는 실제 불일치가 아닙니다.
고정 너비 형식의 차이점은 바이트 수준에서도 보이지 않습니다. 하이픈, 공백 또는 콜론(예: ba-78-16-bf)으로 표시되는 다이제스트는 실제 바이트를 변경하는 것이 아니라 사람이 더 쉽게 읽을 수 있도록 하는 형식 지정 규칙입니다. ToolAcre 도구는 항상 구분 기호 없이 소문자를 내보냅니다. 이는 대부분의 명령줄 도구가 인쇄하는 형식입니다. 다르게 방출하는 도구와 비교하는 경우 먼저 동일한 표현으로 변환하십시오.
여기서 다루지 않는 내용 — 동일한 원칙이 적용되지만 바이트가 텍스트 필드가 아닌 디스크에서 나오는 파일 해싱
ToolAcre SHA 해시 계산기는 해시 전에 UTF-8 변환을 수행하고 입력 바이트 수를 표시하며 base64 및 16진수 출력 형식을 제공합니다. 소스 파일 apps/dev/src/lib/hash.js은 bytes.slice().buffer를 crypto.subtle.digest에 전달하는 DigestBytes를 호출하는 hashText 함수를 보여줍니다. 해당 파일의 주석에는 UTF-8 단계가 의도적인 것임을 명시적으로 문서화하고 다양한 인코딩 간의 차이점을 기록합니다. 알려진 벡터(abc는 16진수로 ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad로 해시됨)에 대해 입력을 테스트하면 브라우저 도구가 올바르게 작동하는 것으로 확인됩니다. 편차는 입력의 바이트 차이를 나타냅니다.
파일 해싱은 동일한 원칙을 따릅니다. 파일의 바이트가 중요합니다. 한 시스템에서 내보낼 때와 다른 시스템으로 가져올 때 줄 끝 차이로 인해 모든 다이제스트가 변경될 수 있습니다. 일부 도구는 비교 중에 줄 끝을 처리하는 옵션을 제공합니다. 다른 사람들은 파일을 있는 그대로 해시합니다. 도구가 파일을 바이너리로 해시하는지 아니면 텍스트 정규화를 먼저 수행하는지 아는 것이 재현성을 위해 필수적입니다.
요약: 텍스트가 아닌 해시 바이트 — ToolAcre SHA 해시 계산기는 붙여넣은 바이트를 해시하므로 먼저 붙여넣은 내용을 확인하세요.
비교 및 확인은 동일한 바이트를 해시하는 경우에만 작동합니다. 정확히 동일한 입력을 해싱하고 있는지 확인하는 것부터 시작하세요. 개행을 방지하려면 echo 대신 echo -n(또는 printf)을 실행하고, 도구에서 허용하는 경우 명시적으로 UTF-8 인코딩을 지정하고, 편집기나 시스템 유틸리티에 의해 CRLF가 삽입되지 않았는지 확인하세요. 그런 다음 ToolAcre 계산기와 명령줄 도구를 나란히 사용하여 해시합니다. 다이제스트가 일치하면 바이트가 동일한 것입니다. 그렇지 않은 경우 바이트 수 표시 및 16진수 덤프 방법을 사용하여 숨겨진 차이점을 찾으십시오.
바이트가 어디에서 갈라졌는지 파악한 후에는 비교를 위해 정규화할지 여부를 선택할 수 있습니다. 일부 체크섬은 디스크에 있는 그대로 파일 무결성을 확인하기 위한 것이며, 이 경우 바이트 단위 해싱이 목표입니다. 다른 것들은 보이는 내용이 동일한지 확인하기 위한 것이며, 이 경우 줄 끝 정규화 및 인코딩이 올바른 것입니다. 둘 다 틀린 것은 아닙니다. 그들은 다른 질문에 대답합니다. SHA-256 알고리즘은 항상 옳습니다. 문제는 두 경우 모두 동일한 입력을 해시하도록 요청하는지 여부입니다.