【Java】 Java で、シリアル番号生成を考える

はじめに

 * Java で、シリアル番号生成を考えていたら、以下のサイトを見つけたので参考にして実装してみる
http://www.venishjoe.net/2009/08/basic-serial-key-generation-module-in.html

参考:シリアル番号に関わるトラブル

http://www.barcode-net.com/chisiki/serial_number.html
http://takahitokikuchi.poitan.net/2012/11/03/%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E3%82%84%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB%E7%95%AA%E5%8F%B7%EF%BC%88%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%89%EF%BC%89%E3%81%AE/
 * 以下の文字が紛らわしく間違うトラブルがあるとかないとか...

  + 数字の「0(ゼロ)」と英字の「O(オー)」
  + 数字の「1(イチ)」と英字の「l(エル)」or「I(アイ)」
  + 数字の「8(ハチ)」と英字の「B(ビー)」

 => カタカナで振り仮名振るなどの対策が必要かも...

 ※そのプログラムを書いてみた。以下の関連記事を参照のこと。
http://blogs.yahoo.co.jp/dk521123/36586289.html

サンプル

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Main {

  private static final String DELIMITTER = "-";

  public static void main(String[] args) throws NoSuchAlgorithmException {

    String input = "1234567890123456789012345678901234567890";

    String serialNumber = createSerialNumber(input);
    System.out.println("SN : " + serialNumber + " Valid? " + isValidSerialNumber(serialNumber, input));
    System.out.println("SN : f71sX-6ec5e-f68s5-b4d00 Valid? " + isValidSerialNumber("f71sX-6ec5e-f68s5-b4d00", input));

    System.out.println("+++++++++++++++++++++++++++++++++++");
    
    String input2 = "526252";
    serialNumber = createSerialNumber(input, input2);
    System.out.println("SN : " + serialNumber + " Valid? " + isValidSerialNumber(serialNumber, input, input2));
    System.out.println("SN : f71sX-6ec5e-f68s5-b4d00 Valid? " + isValidSerialNumber("f71sX-6ec5e-f68s5-b4d00", input, input2));
  }

  private static String createSerialNumber(String... sourceValues) throws NoSuchAlgorithmException {
    try {
      String sourceValue = "";
      for (String value : sourceValues) {
        sourceValue = sourceValue + value;
      }
      
      String serialNumberEncodedForMd5 = calculateSecurityHash(sourceValue, "MD5");
      sourceValue = sourceValue + serialNumberEncodedForMd5;
      String serialNumberEncodedForSha1 = calculateSecurityHash(sourceValue, "SHA1");
      sourceValue = sourceValue + serialNumberEncodedForSha1;
      String serialNumberEncodedForMd2 = calculateSecurityHash(sourceValue, "MD2");

      String serialNumberEncoded = serialNumberEncodedForMd2 + serialNumberEncodedForMd5 + serialNumberEncodedForSha1;

      StringBuilder serialNumber = new StringBuilder();
      serialNumber.append(serialNumberEncoded.charAt(12));
      serialNumber.append(serialNumberEncoded.charAt(101));
      serialNumber.append(serialNumberEncoded.charAt(23));
      serialNumber.append(serialNumberEncoded.charAt(97));
      serialNumber.append(serialNumberEncoded.charAt(79));
      serialNumber.append(DELIMITTER);
      serialNumber.append(serialNumberEncoded.charAt(76));
      serialNumber.append(serialNumberEncoded.charAt(1));
      serialNumber.append(serialNumberEncoded.charAt(21));
      serialNumber.append(serialNumberEncoded.charAt(3));
      serialNumber.append(serialNumberEncoded.charAt(43));
      serialNumber.append(DELIMITTER);
      serialNumber.append(serialNumberEncoded.charAt(11));
      serialNumber.append(serialNumberEncoded.charAt(46));
      serialNumber.append(serialNumberEncoded.charAt(35));
      serialNumber.append(serialNumberEncoded.charAt(9));
      serialNumber.append(serialNumberEncoded.charAt(81));
      serialNumber.append(DELIMITTER);
      serialNumber.append(serialNumberEncoded.charAt(39));
      serialNumber.append(serialNumberEncoded.charAt(94));
      serialNumber.append(serialNumberEncoded.charAt(54));
      serialNumber.append(serialNumberEncoded.charAt(25));
      serialNumber.append(serialNumberEncoded.charAt(44));

      return serialNumber.toString();
    } catch (NoSuchAlgorithmException ex) {
      ex.printStackTrace();
      throw ex;
    }
  }

  private static boolean isValidSerialNumber(String serialNumber, String... sourceValues) throws NoSuchAlgorithmException {
    String sourceSerialNumber = createSerialNumber(sourceValues);

    return sourceSerialNumber.equals(serialNumber);
  }

  private static String calculateSecurityHash(String targetValue, String algorithm)
      throws java.security.NoSuchAlgorithmException {
    byte[] targetValueBytes = targetValue.getBytes();
    MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
    messageDigest.update(targetValueBytes);
    byte[] messageDigestBytes = messageDigest.digest();
    return DatatypeConverter.printHexBinary(messageDigestBytes);
  }
}

出力結果

SN : 93a60-c2682-b6f52-8d0fa Valid? true
SN : f71sX-6ec5e-f68s5-b4d00 Valid? false
+++++++++++++++++++++++++++++++++++
SN : 58977-8c422-5bf07-48e96 Valid? true
SN : f71sX-6ec5e-f68s5-b4d00 Valid? false

参考文献

 * 別の方法で生成しているサイト
http://shtpg.blog16.fc2.com/blog-entry-7.html

関連記事

セキュアなランダム文字列生成を考える

http://blogs.yahoo.co.jp/dk521123/36415526.html

ハッシュで暗号化する

http://blogs.yahoo.co.jp/dk521123/33829893.html

動的計画法フィボナッチ数列 を例にして~

http://blogs.yahoo.co.jp/dk521123/34536896.html

シリアル番号やパスワードの読みを振り仮名に変換するプログラムを考える

http://blogs.yahoo.co.jp/dk521123/36586289.html