HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

各言語でメッセージダイジェスト

手元にある各言語で、メッセージダイジェストを出力してみたメモ。

要件は以下の通り。

  • 標準入力から、0バイト以上の任意のバイト列が入力される
  • 標準出力に、入力に対する以下のハッシュ文字列を改行区切りで出力する
    • MD5
    • SHA-1
    • SHA-224
    • SHA-256
    • SHA-384
    • SHA-512

環境

手元にあるものということで、環境は以下のものに限定する。

入力

Hello World!

出力

8ddd8be4b179a529afa5f2ffae4b9858
a0b65939670bc2c010f4d5d6a0b3e4e4590fb92b
de9d76f0f6a015ab6629138a42835e7b44571995e4abb291c0817261
03ba204e50d126e4674c005e04d82e84c21366780af1f43bd54a37816b6ab340
07f60df0b95043b3a3717638e7776ab76ebaa4fc705ba659063229cf162980c04a9f7496dcda50de6510d40fde3eba8a
830445e86a0cfafac4e1531002356f384847a11a7456fb8ccb81ab36e37bff28f34fa2c5bfdd347e964c5c5df0fc305de6394368219307b2ceeb0ec84b7c2b31

Java

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Main {
    public static void main(String[] args) throws NoSuchAlgorithmException {
        MessageDigest[] mdAry = {
            MessageDigest.getInstance("MD5"),
            MessageDigest.getInstance("SHA-1"),
            MessageDigest.getInstance("SHA-224"),
            MessageDigest.getInstance("SHA-256"),
            MessageDigest.getInstance("SHA-384"),
            MessageDigest.getInstance("SHA-512"),
        };
        try (InputStream in = new BufferedInputStream(System.in)) {
            byte[] b = new byte[1024];
            int len;
            while ((len = in.read(b)) > 0) {
                for (MessageDigest md : mdAry) {
                    md.update(b, 0, len);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        for (MessageDigest md : mdAry) {
            byte[] digest = md.digest();
            for (byte b : digest) {
                System.out.printf("%02x", b);
            }
            System.out.println();
        }
    }
}

C

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

int main(int argc, char** argv) {
    MD5_CTX md5_ctx;
    unsigned char md5[MD5_DIGEST_LENGTH];
    SHA_CTX sha1_ctx;
    unsigned char sha1[SHA_DIGEST_LENGTH];
    SHA256_CTX sha224_ctx;
    unsigned char sha224[SHA224_DIGEST_LENGTH];
    SHA256_CTX sha256_ctx;
    unsigned char sha256[SHA256_DIGEST_LENGTH];
    SHA512_CTX sha384_ctx;
    unsigned char sha384[SHA384_DIGEST_LENGTH];
    SHA512_CTX sha512_ctx;
    unsigned char sha512[SHA512_DIGEST_LENGTH];

    if (!MD5_Init(&md5_ctx)) {
        return 1;
    }
    if (!SHA1_Init(&sha1_ctx)) {
        return 1;
    }
    if (!SHA224_Init(&sha224_ctx)) {
        return 1;
    }
    if (!SHA256_Init(&sha256_ctx)) {
        return 1;
    }
    if (!SHA384_Init(&sha384_ctx)) {
        return 1;
    }
    if (!SHA512_Init(&sha512_ctx)) {
        return 1;
    }

    char buf[1024];
    int len;
    while ((len = fread(buf, sizeof(char), sizeof(buf), stdin)) > 0) {
        if (!MD5_Update(&md5_ctx, buf, len)) {
            return 1;
        }
        if (!SHA1_Update(&sha1_ctx, buf, len)) {
            return 1;
        }
        if (!SHA224_Update(&sha224_ctx, buf, len)) {
            return 1;
        }
        if (!SHA256_Update(&sha256_ctx, buf, len)) {
            return 1;
        }
        if (!SHA384_Update(&sha384_ctx, buf, len)) {
            return 1;
        }
        if (!SHA512_Update(&sha512_ctx, buf, len)) {
            return 1;
        }
    }

    if (!MD5_Final(md5, &md5_ctx)) {
        return 1;
    }
    if (!SHA1_Final(sha1, &sha1_ctx)) {
        return 1;
    }
    if (!SHA224_Final(sha224, &sha224_ctx)) {
        return 1;
    }
    if (!SHA256_Final(sha256, &sha256_ctx)) {
        return 1;
    }
    if (!SHA384_Final(sha384, &sha384_ctx)) {
        return 1;
    }
    if (!SHA512_Final(sha512, &sha512_ctx)) {
        return 1;
    }

    for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
        fprintf(stdout, "%02x", md5[i]);
    }
    fprintf(stdout, "\n");
    for (int i = 0; i < SHA_DIGEST_LENGTH; ++i) {
        fprintf(stdout, "%02x", sha1[i]);
    }
    fprintf(stdout, "\n");
    for (int i = 0; i < SHA224_DIGEST_LENGTH; ++i) {
        fprintf(stdout, "%02x", sha224[i]);
    }
    fprintf(stdout, "\n");
    for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
        fprintf(stdout, "%02x", sha256[i]);
    }
    fprintf(stdout, "\n");
    for (int i = 0; i < SHA384_DIGEST_LENGTH; ++i) {
        fprintf(stdout, "%02x", sha384[i]);
    }
    fprintf(stdout, "\n");
    for (int i = 0; i < SHA512_DIGEST_LENGTH; ++i) {
        fprintf(stdout, "%02x", sha512[i]);
    }
    fprintf(stdout, "\n");

    return 0;
}

「-lcrypto」を付けてコンパイルする必要がある。

C++

C言語と大して変わらないけど、一応載せておく。

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

int main(int argc, char** argv) {
    MD5_CTX md5_ctx;
    unsigned char md5[MD5_DIGEST_LENGTH];
    SHA_CTX sha1_ctx;
    unsigned char sha1[SHA_DIGEST_LENGTH];
    SHA256_CTX sha224_ctx;
    unsigned char sha224[SHA224_DIGEST_LENGTH];
    SHA256_CTX sha256_ctx;
    unsigned char sha256[SHA256_DIGEST_LENGTH];
    SHA512_CTX sha384_ctx;
    unsigned char sha384[SHA384_DIGEST_LENGTH];
    SHA512_CTX sha512_ctx;
    unsigned char sha512[SHA512_DIGEST_LENGTH];

    if (!MD5_Init(&md5_ctx)) {
        return EXIT_FAILURE;
    }
    if (!SHA1_Init(&sha1_ctx)) {
        return EXIT_FAILURE;
    }
    if (!SHA224_Init(&sha224_ctx)) {
        return EXIT_FAILURE;
    }
    if (!SHA256_Init(&sha256_ctx)) {
        return EXIT_FAILURE;
    }
    if (!SHA384_Init(&sha384_ctx)) {
        return EXIT_FAILURE;
    }
    if (!SHA512_Init(&sha512_ctx)) {
        return EXIT_FAILURE;
    }

    char buf[1024];
    int len;
    while ((len = fread(buf, sizeof(char), sizeof(buf), stdin)) > 0) {
        if (!MD5_Update(&md5_ctx, buf, len)) {
            return EXIT_FAILURE;
        }
        if (!SHA1_Update(&sha1_ctx, buf, len)) {
            return EXIT_FAILURE;
        }
        if (!SHA224_Update(&sha224_ctx, buf, len)) {
            return EXIT_FAILURE;
        }
        if (!SHA256_Update(&sha256_ctx, buf, len)) {
            return EXIT_FAILURE;
        }
        if (!SHA384_Update(&sha384_ctx, buf, len)) {
            return EXIT_FAILURE;
        }
        if (!SHA512_Update(&sha512_ctx, buf, len)) {
            return EXIT_FAILURE;
        }
    }

    if (!MD5_Final(md5, &md5_ctx)) {
        return EXIT_FAILURE;
    }
    if (!SHA1_Final(sha1, &sha1_ctx)) {
        return EXIT_FAILURE;
    }
    if (!SHA224_Final(sha224, &sha224_ctx)) {
        return EXIT_FAILURE;
    }
    if (!SHA256_Final(sha256, &sha256_ctx)) {
        return EXIT_FAILURE;
    }
    if (!SHA384_Final(sha384, &sha384_ctx)) {
        return EXIT_FAILURE;
    }
    if (!SHA512_Final(sha512, &sha512_ctx)) {
        return EXIT_FAILURE;
    }

    for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
        fprintf(stdout, "%02x", md5[i]);
    }
    fprintf(stdout, "\n");
    for (int i = 0; i < SHA_DIGEST_LENGTH; ++i) {
        fprintf(stdout, "%02x", sha1[i]);
    }
    fprintf(stdout, "\n");
    for (int i = 0; i < SHA224_DIGEST_LENGTH; ++i) {
        fprintf(stdout, "%02x", sha224[i]);
    }
    fprintf(stdout, "\n");
    for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
        fprintf(stdout, "%02x", sha256[i]);
    }
    fprintf(stdout, "\n");
    for (int i = 0; i < SHA384_DIGEST_LENGTH; ++i) {
        fprintf(stdout, "%02x", sha384[i]);
    }
    fprintf(stdout, "\n");
    for (int i = 0; i < SHA512_DIGEST_LENGTH; ++i) {
        fprintf(stdout, "%02x", sha512[i]);
    }
    fprintf(stdout, "\n");

    return EXIT_SUCCESS;
}

「-lcrypto」を付けてコンパイルする必要がある。

PHP

<?php

$input = file_get_contents('php://stdin');

printf("%s\n", hash('md5', $input));
printf("%s\n", hash('sha1', $input));
printf("%s\n", hash('sha224', $input));
printf("%s\n", hash('sha256', $input));
printf("%s\n", hash('sha384', $input));
printf("%s\n", hash('sha512', $input));

メモリに載りきらないほどのデータが来たら対応できないのが難点。

Python 2

import sys
import hashlib

md5 = hashlib.md5()
sha1 = hashlib.sha1()
sha224 = hashlib.sha224()
sha256 = hashlib.sha256()
sha384 = hashlib.sha384()
sha512 = hashlib.sha512()

while True:
    line = sys.stdin.readline()
    if line == '':
        break
    md5.update(line)
    sha1.update(line)
    sha224.update(line)
    sha256.update(line)
    sha384.update(line)
    sha512.update(line)

print md5.hexdigest()
print sha1.hexdigest()
print sha224.hexdigest()
print sha256.hexdigest()
print sha384.hexdigest()
print sha512.hexdigest()

Python 3

import sys
import hashlib

md5 = hashlib.md5()
sha1 = hashlib.sha1()
sha224 = hashlib.sha224()
sha256 = hashlib.sha256()
sha384 = hashlib.sha384()
sha512 = hashlib.sha512()

while True:
    line = sys.stdin.buffer.readline()
    if line == b'':
        break
    md5.update(line)
    sha1.update(line)
    sha224.update(line)
    sha256.update(line)
    sha384.update(line)
    sha512.update(line)

print(md5.hexdigest())
print(sha1.hexdigest())
print(sha224.hexdigest())
print(sha256.hexdigest())
print(sha384.hexdigest())
print(sha512.hexdigest())

Ruby

require 'openssl'

mdAry = [
    OpenSSL::Digest.new("md5"),
    OpenSSL::Digest.new("sha1"),
    OpenSSL::Digest.new("sha224"),
    OpenSSL::Digest.new("sha256"),
    OpenSSL::Digest.new("sha384"),
    OpenSSL::Digest.new("sha512"),
]

while line = STDIN.gets
    for md in mdAry
        md.update(line)
    end
end

for md in mdAry
    puts md.hexdigest
end

Perl

use Digest::MD5;
use Digest::SHA;

my $md5 = Digest::MD5->new();
my $sha1 = Digest::SHA->new("sha1");
my $sha224 = Digest::SHA->new("sha224");
my $sha256 = Digest::SHA->new("sha256");
my $sha384 = Digest::SHA->new("sha384");
my $sha512 = Digest::SHA->new("sha512");

while (my $line = readline(STDIN)) {
    $md5->add($line);
    $sha1->add($line);
    $sha224->add($line);
    $sha256->add($line);
    $sha384->add($line);
    $sha512->add($line);
}

print $md5->hexdigest(),"\n";
print $sha1->hexdigest(),"\n";
print $sha224->hexdigest(),"\n";
print $sha256->hexdigest(),"\n";
print $sha384->hexdigest(),"\n";
print $sha512->hexdigest(),"\n";

yum install perl-Digest-MD5 perl-Digest-SHA」が必要。

Go

package main

import (
    "fmt"
    "io"
    "os"
    "crypto/md5"
    "crypto/sha1"
    "crypto/sha256"
    "crypto/sha512"
)

func main() {
    aMd5 := md5.New()
    aSha1 := sha1.New()
    aSha224 := sha256.New224()
    aSha256 := sha256.New()
    aSha384 := sha512.New384()
    aSha512 := sha512.New()

    for {
        buf := make([]byte, 1024)
        n, err := os.Stdin.Read(buf)
        if err == io.EOF {
            break
        }
        buf2 := make([]byte, 0);
        buf2 = append(buf2, buf[0:n]...)

        aMd5.Write(buf2)
        aSha1.Write(buf2)
        aSha224.Write(buf2)
        aSha256.Write(buf2)
        aSha384.Write(buf2)
        aSha512.Write(buf2)
    }

    fmt.Printf("%x\n", aMd5.Sum(nil))
    fmt.Printf("%x\n", aSha1.Sum(nil))
    fmt.Printf("%x\n", aSha224.Sum(nil))
    fmt.Printf("%x\n", aSha256.Sum(nil))
    fmt.Printf("%x\n", aSha384.Sum(nil))
    fmt.Printf("%x\n", aSha512.Sum(nil))
}

bash

#! /bin/bash

cat | tee \
    >(sha512sum | cut -d " " -f 1) \
    >(sha384sum | cut -d " " -f 1) \
    >(sha256sum | cut -d " " -f 1) \
    >(sha224sum | cut -d " " -f 1) \
    >(sha1sum | cut -d " " -f 1) \
    >(md5sum | cut -d " " -f 1) \
    >> /dev/null

バイナリデータのテストケースにも対応するためにteeコマンド+コマンド置換を使ったが、期待する順番通りに出力されないことがあるのが難点。

  • man md5sum
  • man sha1sum
  • man sha224sum
  • man sha256sum
  • man sha384sum
  • man sha512sum