2008年1月17日木曜日

「ふっかつのじゅもん」っぽい暗号

昔のゲームに出てきそうなひらがな(64種)による暗号です。
ひらがな1文字(16ビット)で6ビットの情報が表現できますので、情報量は16/6=約2.7倍になります。妙にビット演算が多いので、単純な目的の割に複雑なスクリプトになっています。

カタカナも取り入れれば7ビットの情報が表現できるはずです。また、半角カタカナを使えば情報量を8/6=約1.3倍に抑えられます半角カタカナは濁点・半濁点の表現に1ビット要するので一概には言えません
復元時にinstrによる線形検索を行っているなど、速度上の課題はまだまだあるでしょう。
// 文字列型暗号作成スクリプト

// 参考:テキストボックスの編集監視
//      http://lhsp.s206.xrea.com/hsp_object2.html#4

#define ctype HIWORD(%1) (%1 >> 16 & 0xFFFF)
#module
#include "hspmath.as"
#const SPELL_KEY 0
// モジュールの初期化
#deffunc init_spell
    // 文字列型暗号の素 64文字
    sdim base, 64 * 2 + 1
    base  = "あいうえおかきくけこがぎぐげごさしすせそざじずぜぞ"    // 25文字
    base += "たちつてとだぢづでどなにぬねのはひふへほばびぶべぼ"    // 25 + 25 = 50文字
    base += "まみむめもやゆよらりるれろん"                          // 50 + 14 = 64文字
    return

// 指定した位置(ビット)から6ビットを取り出すマクロ
// バッファオーバーフローに注意
#define ctype peek6(%1%2=0) ((((peek(%1, (%2) / 8) << 8) | peek(%11 + (%2) / 8)) >> (10 - (%2) \ 8)) & 0x3F)

// 指定した位置(ビット)から6ビット書き込む命令
// バッファオーバーフローに注意
#deffunc poke6 var target, int index, int value
    i  = (peek(target, index / 8) << 8) | peek(target, index / 8 + 1)
    i ^= peek6(target, index) << (10 - (index \ 8))
    i |= (value & 0x3F) << (10 - (index \ 8))
    poke target, index / 8, (i >> 8) & 0xFF
    poke target, index / 8 + 1, i & 0xFF
    return

// パスワードから通常の文字列データへ変換
#deffunc spell2str var result, str _before
    before = _before
    len = strlen(before)
    randomize SPELL_KEY
    repeat len / 2
        code = (instr(base, 0strmid(before, cnt * 22)) / 2) ^ rnd(0x40)
        poke6 result, cnt * 6, code
    loop
    poke result, int(ceil(8.0 * len / 6.0)), 0
    return

// 通常の文字列データからパスワードに変換
#deffunc str2spell var result, str _before
    before = _before
    randomize SPELL_KEY
    // 対象となる文字列から6ビットずつ切りだし、ひらがなに変換
    for i, 0strlen(before) * 86
        // XOR演算によって より暗号っぽく
        wpoke result, i / 3wpeek(base, (peek6(before, i) ^ rnd(0x40)) * 2)
    next
    poke result, i / 30
    return
#global
    init_spell


    screen 0240200
    // 元の文字を代入する文字列型変数
    sdim before, 512
    // 文字列型暗号が代入される文字列型変数
    sdim result, 1536
    // テキストボックス作成
    mesbox before, ginfo_winxginfo_winy / 2, , 250
    hInput = objinfo_hwnd(stat)
    mesbox result, ginfo_winxginfo_winy / 2
    idResult = stat
    sendmsg objinfo_hwnd(idResult), $CF1  // 編集無効

    oncmd gosub *command0x0111            // WM_COMMAND
    stop

// テキストボックスの編集を監視する
*command
    if lparam == hInput {
        if HIWORD (wparam) = 0x300 {
            // 編集された場合は文字列型暗号を作って表示
            str2spell result, before
            objprm idResult, result
/*          // この行の"/*"を消すとタイトルに復元した文字列を表示
            sdim s, 512
            spell2str s, result
            title s
//*/

        }
    }
    return

0 件のコメント: