MACアドレスは, デバイスの固有住所や固有名詞的な立ち位置なので, 個人情報に該当すると扱われ, しばしば暗号化して管理することがあります。
MACアドレスの暗号化を自前で実装したり, 解いたりする場合には, 四則演算することが必要です。
今回は, Pythonでoperator overloadingとクラス継承を使って, これらを実装しましょう。
operator overloadingについては, こちらの記事を参考にしてください。
operator overloadでオリジナルの演算子を実装 for Python - werry-chanの日記.料理とエンジニアリング
まずは, 親クラスとして, 符号なしN進数クラスを作ります。
# this code is werry-chann lib # this lib provide oct hex unsigned class class unsigned_int: def __init__(self, val, upper_lim=256): self.val = val self.upper_lim = upper_lim self.check_val() def show(self): print(self.val, end="") def check_val(self): self.val = int(self.val % self.upper_lim)
表示 show() 関数とN進数チェック check_val() 関数も作っておきました。
次はこのクラス間で四則演算できるように, 演算子を定義します。
# this code is werry-chann lib # this lib provide oct hex unsigned class import copy class unsigned_int: def __init__(self, val, upper_lim=256): self.val = val self.upper_lim = upper_lim self.check_val() def show(self): print(self.val, end="") def check_val(self): self.val = int(self.val % self.upper_lim) def to_myclass(self, val): temp = copy.deepcopy(self) temp.val = val return temp def __add__(self, add_uint): if type(self) != add_uint.__class__: add_uint = self.to_myclass(add_uint) ret_uint = copy.deepcopy(self) ret_uint.val += add_uint.val ret_uint.check_val() return ret_uint def __sub__(self, sub_uint): if type(self) != sub_uint.__class__: sub_uint = self.to_myclass(sub_uint) ret_uint = copy.deepcopy(self) ret_uint.val -= sub_uint.val ret_uint.check_val() return ret_uint def __mul__(self, mul_uint): if type(self) != mul_uint.__class__: mul_uint = self.to_myclass(mul_uint) ret_uint = copy.deepcopy(self) ret_uint.val *= mul_uint.val ret_uint.check_val() return ret_uint def __truediv__(self, dev_uint): if type(self) != dev_uint.__class__: dev_uint = self.to_myclass(dev_uint) ret_uint = copy.deepcopy(self) ret_uint.val /= dev_uint.val ret_uint.check_val() return ret_uint class unsigned_hex(unsigned_int): def __init__(self, val): super().__init__(val, upper_lim=8) class unsigned_oct(unsigned_int): def __init__(self, val): super().__init__(val, upper_lim=16)
演算子を定義するついでに, クラス継承で8進数と16進数を作っておきました。
それでは, 目的のMACアドレスのクラスを作ってみましょう。
典型的なMACアドレスは
F1:10:0B:16:FD:3A
のように, 16進数 2桁 6個で構成されています。
先ほど作成したunsigned_intクラスを使って実装します。
16進数2桁なので, 256=16^2, unsigned_intのupper_limはdefault引数256が使えますので, 省略可能です。
今回は入力される文字列にspace, tabなどは考慮せず, 必ず2桁以下, 正の値で入力されることを前提に実装していきます。
class mac_address: def __init__(self, str_digits, digits=6, upper_lim=256): self.digits = digits self.val_list = str_digits.split(':') for i in range(len(self.val_list)): self.val_list[i] = unsigned_int( int('0x' + str(self.val_list[i]), 0) ) def show(self): for i in range(len(self.val_list)): self.val_list[i].show(); print(",", end="")
__init__()初期化関数でlistに各値を保持しています。
16進数の文字列の先頭に'0x'をつけてint('0x' + str(val), 0)としてやると
文字列からintの数値として読み込めます。
では先ほどの符号なしN進数の実装と同様に演算子を作成しましょう。
class mac_address: def __init__(self, str_digits, digits=6, upper_lim=256): self.digits = digits self.val_list = str_digits.split(':') for i in range(len(self.val_list)): self.val_list[i] = unsigned_int( int('0x' + str(self.val_list[i]), 0) ) def show(self): for i in range(len(self.val_list)): self.val_list[i].show(); print(",", end="") def __add__(self, add_digits): ret_digits = copy.deepcopy(self) for i in range(self.digits): ret_digits.val_list[i] += add_digits.val_list[i] return ret_digits def __sub__(self, sub_digits): ret_digits = copy.deepcopy(self) for i in range(self.digits): ret_digits.val_list[i] -= sub_digits.val_list[i] return ret_digits def __mul__(self, mul_digits): ret_digits = copy.deepcopy(self) for i in range(self.digits): ret_digits.val_list[i] *= mul_digits.val_list[i] return ret_digits def __truediv__(self, dev_digits): ret_digits = copy.deepcopy(self) for i in range(self.digits): ret_digits.val_list[i] /= dev_digits.val_list[i] return ret_digits
やっとのことで演算可能なMACアドレスの自作クラスが完成しました。
普通はMACアドレスて基本は固定値か乱数なので, 演算しようとする人はいないので, めちゃくちゃ使いどころが限られるクラスになります。
自作するしかないですね。
以下に全コード載せておきます。
# this code is werry-chann lib # this lib provide oct hex unsigned class import copy class unsigned_int: def __init__(self, val, upper_lim=256): self.val = val self.upper_lim = upper_lim self.check_val() def show(self): print(self.val, end="") def check_val(self): self.val = int(self.val % self.upper_lim) def to_myclass(self, val): temp = copy.deepcopy(self) temp.val = val return temp def __add__(self, add_uint): if type(self) != add_uint.__class__: add_uint = self.to_myclass(add_uint) ret_uint = copy.deepcopy(self) ret_uint.val += add_uint.val ret_uint.check_val() return ret_uint def __sub__(self, sub_uint): if type(self) != sub_uint.__class__: sub_uint = self.to_myclass(sub_uint) ret_uint = copy.deepcopy(self) ret_uint.val -= sub_uint.val ret_uint.check_val() return ret_uint def __mul__(self, mul_uint): if type(self) != mul_uint.__class__: mul_uint = self.to_myclass(mul_uint) ret_uint = copy.deepcopy(self) ret_uint.val *= mul_uint.val ret_uint.check_val() return ret_uint def __truediv__(self, dev_uint): if type(self) != dev_uint.__class__: dev_uint = self.to_myclass(dev_uint) ret_uint = copy.deepcopy(self) ret_uint.val /= dev_uint.val ret_uint.check_val() return ret_uint class unsigned_hex(unsigned_int): def __init__(self, val): super().__init__(val, upper_lim=8) class unsigned_oct(unsigned_int): def __init__(self, val): super().__init__(val, upper_lim=16) class mac_address: def __init__(self, str_digits, digits=6, upper_lim=256): self.digits = digits self.val_list = str_digits.split(':') for i in range(len(self.val_list)): self.val_list[i] = unsigned_int( int('0x' + str(self.val_list[i]), 0) ) def show(self): for i in range(len(self.val_list)): self.val_list[i].show(); print(",", end="") def __add__(self, add_digits): ret_digits = copy.deepcopy(self) for i in range(self.digits): ret_digits.val_list[i] += add_digits.val_list[i] return ret_digits def __sub__(self, sub_digits): ret_digits = copy.deepcopy(self) for i in range(self.digits): ret_digits.val_list[i] -= sub_digits.val_list[i] return ret_digits def __mul__(self, mul_digits): ret_digits = copy.deepcopy(self) for i in range(self.digits): ret_digits.val_list[i] *= mul_digits.val_list[i] return ret_digits def __truediv__(self, dev_digits): ret_digits = copy.deepcopy(self) for i in range(self.digits): ret_digits.val_list[i] /= dev_digits.val_list[i] return ret_digits if __name__ == "__main__": ui = unsigned_hex(5) ui_ = unsigned_hex(7) (ui_ - 20 ).val; print() (ui / ui_).show; print() ma0 = mac_address( '6:10:2B:C0:0D:34') ma1 = mac_address('F1:10:0B:16:FD:3A') ma0.show(); print() ma1.show(); print() (ma0 - ma1).show(); print() (ma0 + ma1).show(); print() (ma0 * ma1).show(); print() (ma0 / ma1).show(); print()