認証の基礎

その人だけが知っている知識を利用した認証を知識認証という
指紋や静脈など生体情報を利用した生体認証
ワンタイムパスワード生成器などを利用した所有物認証がある
ユーザごとに発行するクライアント証明書を発行する方法もある
L パスワード認証が成功したら、次に登録したスマートフォンに認証コードが送られてきてそのコードを入力して初めてログインできるシステムが増えている
  L PHPでSMS送信するにはTwillioやClickatellが提供しているものを使うのが簡単
   L フレームワークで公開されているものがある
https://github.com/fotografde/cakephp-sms

### 認可
ユーザの属性に応じてシステムのアクセス権限を決める

### OAuth
YがXのAPIを利用できるよう認可する その標準的な枠組みがRFC6749で定義されたOAuth2.0
パスワードの代わりにアクセストークンと呼ばれるデータを用いてYがXのリソースにアクセスする

ブルートフォース(Brute-force)攻撃

$http->post('username', '****')
	->post('password', '****')
	->post('action', 'login2')
	->fetch('https://www.value-domain.com/login.php');

CSRF対策トークンがないと簡単に攻撃されてしまう

### hydraでBrute-force
$ crunch 4 4 -o password.txt
$ hydra -l test -P password.txt 127.0.0.1 http-post-form ‘/login_sql.php:name=^USER^&password=^PASS^:ログイン失敗です’

hydra github
https://github.com/vanhauser-thc/thc-hydra

### Pythonで4桁のパスワードのBrute-force攻撃

import zipfile
import pandas as pd

file_path = 'energy.zip'
size = 4
chars = '0123456789'
count = 0
numbers = []

with zipfile.ZipFile(file_path . 'r') as zf:
	for i in range(100000):
		pwd = bytes(''.join(random.choices(chars, k=size)), 'UTF-8')
		numbers.append(pwd)
		try:
			zf.extractall(path='.'. pwd=pwd)
			print('このPDFファイルのパスワードは、[]です'.format(pwd))
			break
		except Exception as e:
			count += 1

print('総当たり攻撃で解凍を試した回数は:' . count . '回です')
df = pd.DataFrame(numbers)

暗号化

平文を暗号化することをencrypt、復号することをdecrypt
暗号化に使う鍵を暗号鍵
複合に使う鍵を複合鍵(秘密鍵)
L 暗号化ライブラリは広く使われている方が安全性が高いとされる

# 認証
### パスワードの攻撃方法
– 全パターンのパスワードを順次試すブルートフォース(Brute-force)攻撃
– 「12345678」「password」などよく使われるパスワードを入手しておき順次試す辞書攻撃
L 複数回間違えたらロックしたり、弱いパスワードを登録しようとしたら警告を出す
– パスワードを固定してIDを準に試すのをリバースブルート攻撃という
– 多数のユーザIDのリストを持ち、各IDに対して同じパスワードを順次試す方法

なるほど、触りでもかなり奥の深いトピックやな

pkcs#5方式

ブロック暗号方式の場合、平文の文字数をブロック長の倍数に合わせるように、末尾に文字を足すなどの処理を行う必要がある。
ブロック暗号方式において文字を足すことをパディングと呼ぶ。

PKCS#7 パディングはRFC5652で定義されたパディング方式
pkcs#5 パディングは8バイトを倍数とした場合のパディング

なるほど、ちょっとモヤモヤしますな..

Rijndael-128とは

AESは鍵長128, 192, 256bitから選択できる
Rijndaelはブロック長も128, 192, 256bitから選択できる

$key = "秘密の合言葉";
$text = "暗号化するメッセージ";

srand();

$size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($size, MCRYPT_RAND);

$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv);
$hex = bin2hex($encrypted);

$bin = pack("H*", $hex);
$decrptyed = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv);

echo $text . "=>".rtrim($decrypted);

あれ、なんかおかしい。。

PythonでRSA暗号を実装したい

RSAは公開鍵暗号の一つ
暗号文 = 平文^E mod N {E, N}が公開鍵
平文 = 暗号文^D mod N {D, N}が秘密鍵

E, D, Nを求めるには素数を使う
N = p * q
L = lmc(p – 1, q – 1) # lmcとは最小公倍数(Least Common Multiple)
1 < E < L gcd(E,L) = 1 # gcdとは最大公約数、 E, Lは互いに素な整数 1 < D < L (E・D) mod L = 1 # DはEとの積の余剰が1となる任意の整数

from math import gcd

def lcm(p, q):
	return (p * q) // gcd(p, q)

def generate_keys(p, q):
	N = p * q
	L = lcm(p – 1, q – 1)

	for i in range(2, L):
		if gcd(i, L) == 1:
			E = i
			break

	for i in range(2, L):
		if(E * i) % L == 1:
			D = i
			break

	return (E, N), (D, N)

def encrypt(plain_text, public_key):
	E, N = public_key
	plain_integers = [ord(char) for char in plain_text]
	encrypted_integers = [pow(i, E, N) for i in plain_integers]
	encrypted_text = ”.join(chr(i) for i in encrypted_integers)

	return encrypted_text

def decrypt(encrypted_text, private_key):
	D, N = private_key
	encrypted_integers = [ord(char) for char in encrypted_text]
	decrypted_integers = [pow(i, D, N) for i in encrypted_integers]
	decrypted_text = ”.join(chr(i) for i in decrypted_integers)

	return decrypted_text

def sanitize(encrypted_text):

	return encrypted_text.encode(‘utf-8’, ‘replace’).decode(‘utf-8’)

if __name__ == ‘__main__’:
	public_key, private_key = generate_keys(101, 3259)

	plain_text = ‘おはようございます’
	encrypted_text = encrypt(plain_text, public_key)
	decrypted_text = decrypt(encrypted_text, private_key)

	print(f”’
		秘密鍵: {public_key}
		公開鍵: {private_key}

		平文: 「{plain_text}」

		暗号文:
		「{sanitize(encrypted_text)}」

		平文(複合後):
		「{decrypted_text}」
		”'[1:-1])

なるほど、crypto currencyは暗号通貨ってことね

Mcrypt

This function is an extensive block algorithm such as CBC, OFB, CFB, ECB cipher modes DES, TripleDES, Blowfish (default), 3-WAY, SAFER-SK64, SAFER-SK128, TWOFISH, TEA, RC2 and GOST. Interface to the mcrypt library to support. In addition, it supports RC6 and IDEA, which are described as “not free”.

Alice and Bob

from urllib import urlopen, urlencode
import json

base = "http://hgehoge.com"
Alice = base + "/alice"
Bob = base + "bob"

def check_output(output):
	data = output.read()
	if output.getcode() != 200:
		raise Exception(data)
	data = json.loads(data)
	return data

def get_pg():
	output = urlopen(base)
	data = check_output(output)
	return data

def initialize(person):
	data = {'type':'init'}
	output = urlopen(person, urlencode(data))
	data = check_output(output)
	return data

def send_key(person, token, public, name):
	data = {'type':'key',
		'token':token,
		'public': public,
		'name':name}
	output = urlopen(person, urlencode(data))
	data = check_output(output)
	return data

daf recieve_msg(person, token):
	data = {'type':'msg',
			'token':token}
	output = urlopen(person, urlencode(data))
	data = check_output(output)
	return data

def send_msg(person, token, cipher, iv):
	data = {'type':'msg',
			'token':token,
			'message':cipher,
			'iv':iv}
	output = urlopen(person, urlencode(data))
	data = check_output(output)
	return data

a≡b (mod c)

a≡b (mod c) は a-bがcで割り切れること。
10≡0 (mod 5)
14≡5 (mod 3)
13≡-3 (mod 2)

from Crypto.Util.number import inverse
def message_value(message):
	message = bits_to_string(pad_to_block(convert_to_bits(message), 8))
	return cutchoose.bill_value(message)

def remove_nonce(bill, nonce):
	big_nonce = pow(nonce, cutchoose.BANK_PUBLIC_KEY[0], cutchoose.BANK_PUBLIC_KEY[1])
	nonce_inverse = inverse(big_nonce, cutchoose.BANK_PUBLIC_KEY[1])
	message = (bill * nonce_inverse) % cutchoose.BANK_PUBLIC_KEY[1]
	return message

def _verify(bills, nonces, value):
	for bill, nonce in zip(bills, nonces):
		message = remove_nonce(Bill, nonce)
		test_value = message_value(message)
		if test_value != value:
			return False

Cut and choose

import cutchoose
from unit6_util import string_to_bits, bits_to_int, pad_to_block, bits_to_string, convert_to_bit

def _verify(bills, nonces, value):
	return False
cutchoose.verify = _verify

def test():
	bills = cutchoose.generate_bills(50)
	i = cutchoose.pick_and_sign_bills(bills)
	nonces = cutchoose.send_nonces(i)
	signed = cutchoose.verify_bills_and_return_signed(nonces, 50)
	assert signed is not None 
	assert bills[i] == pow(signed, cutchoose.BANK_PUBLIC_KEY[0],
						cutchoose.BANK_PUBLIC_KEY[1])

	bills = cutchoose.cheat_generate_bills(50, 100)
	i = cutchoose.pick_and_sign_bills(bills)
	nonces = cutchoose.send_nonces(i)
	signed = cutchoose.verify_bills_and_return_signed(nonces, 50)
	assert signed is None