メインコンテンツまでスキップ

OpenLDAP の slappasswd で生成される SSHA とは

· 約2分
ひかり
Main bloger

slappasswd コマンドとは

slappasswd コマンドは OpenLDAP 用のパスワードを生成するコマンドで、 デフォルトでは SSHA を用いて、パスワードをハッシュ化する。

graph TD
pass["Password: 'admin'"]
ssha["{SSHA}23AUBfRZytVFNpe7onuFhyCSJOHRzCWh"]
pass -- slappasswd --> ssha

認証の仕組み

SSHA では生成されたハッシュの末尾 4 バイトがソルトとなっており、 入力されたパスワードと保存されているソルトからハッシュを生成し、 保存されているハッシュと一致するかどうかで認証を行う。

graph TD
pass["Password: 'admin' + Salt: D1 CC 25 A1"]
pass -- SHA --> ssha["SSHA: DB 70 14 5 F4 59 CA D5 45 36 97 BB A2 7B 85 87 20 92 24 E1"]
salt["Salt: D1 CC 25 A1"] -- "Base64 (encode)" --> sshabase64
ssha -- "Base64 (encode)" --> sshabase64["23AUBfRZytVFNpe7onuFhyCSJOHRzCWh"]

以下のプログラムでは、 適切なパスワード (例: admin) を与えると、元のハッシュと生成されたハッシュが一致する。

require 'base64'
require 'digest'

pass = 'admin'
ssha = '{SSHA}23AUBfRZytVFNpe7onuFhyCSJOHRzCWh'
ssha =~ /{.+}(.+)/
salt256s = Base64.decode64(Regexp.last_match(1)).unpack('C*')[-4..-1]

salt = salt256s.pack('C*')
b_ssha = Digest::SHA1.digest(pass + salt)
Base64.strict_encode64(
(b_ssha.unpack('C*') + salt256s).pack('C*')
)

Poetry を用いた Python プロジェクトの作成

· 約3分
ひかり
Main bloger

環境構築

Python と Poetry がインストール済みの場合はスキップ

pyenv と Python のインストール

インストール済みの場合はスキップ

参考: https://github.com/pyenv/pyenv-installer

# 依存パッケージのインストール
sudo apt update
sudo apt install make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev

curl https://pyenv.run | bash

~/.bashrc にパスを通す

.bashrc
export PATH=$PATH:~/.pyenv/bin
eval "$(pyenv init --path)"
eval "$(pyenv virtualenv-init -)"

次に Python のインストールを行う。

# インストール可能なバージョン一覧を表示
pyenv install -l
# Python 3.10.2 をインストール
pyenv install 3.10.2

# バージョンの設定
pyenv global 3.10.2
# バージョンの確認
pyenv versions

Poetry のインストール

インストール済みの場合はスキップ

pip install --upgrade pip
pip install poetry

Python プロジェクトの作成

ひな形を作成

プロジェクト名を myapp として、Python プロジェクトを作成する。

poetry new myapp

pyproject.toml にプロジェクトの設定を記述する。

  • ./
    • README.rst
    • myapp/ (Python のコードがあるところ)
      • _init_.py
    • pyproject.toml (プロジェクトの設定ファイル)
    • tests/ (テストコードがあるところ)
      • _init_.py
      • test_myapp.py

./ 上で import myapp すると、myapp/__init__.py が読み込まれる。

プロジェクトに再利用可能な Python コードを追加

例: myapp/ 下に hoge.py を作成する。

  .
├── README.rst
├── myapp
│ ├── __init__.py
+ │ └── hoge.py
├── pyproject.toml
└── tests
├── __init__.py
└── test_myapp.py

2 directories, 6 file

./ 上で from myapp import hoge をすると、hoge.py が読み込まれる。

例: hoge.py の関数を利用する

myapp/hoge.py
def hello():
print('Hello, world!')

./ 上で以下を実行すると、hello() を呼び出し可能。クラスも同様。

>>> from myapp.hoge import hello
>>> hello()
Hello, world!

パッケージの追加

依存するパッケージが必要な場合は、poetry add を実行する。 削除は poetry remove

例: numpy を追加

poetry add numpy

パッケージの作成

myapp パッケージを作成する。 プロジェクトをライブラリとしてインストール・利用が可能に。

poetry build

dist/ 下に whell と tarball が作成される。

作成されたパッケージは pip コマンドでインストール可能。

pip install dist/myapp-0.1.0.tar.gz

プロジェクトをパッケージとして配布

(後日、追記予定)

Blog 環境の移行

· 約1分
ひかり
Main bloger

ブログの環境を jekyll から Docusaurus に移行しました。 アクセスの多い記事に関しては jekyll から移行予定です。

Python で極値の検出

· 約2分
ひかり
Main bloger

概要

信号の極値を検出する。

信号の生成

例として疑似的な信号を生成する。

  • 3 [Hz] の信号 + 0.01 [Hz] の信号 + ノイズ
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy import signal

t = np.arange(30 * 100) / 100
x = np.sin(2 * np.pi * t / 3) + np.random.randn(len(t)) * 0.2 + np.sin(2 * np.pi * t / 100)
df = pd.DataFrame({'Data': x}, index=pd.to_datetime(t, unit='s').time)

fig, ax = plt.subplots()
df.plot(ax=ax, xlim=['00:00:00', '00:00:10'])
plt.show()

tmp

信号の性質を調べる

def acorr(df: pd.DataFrame, ra: int = 3, fs=100):
x = np.correlate(df.Data.values, df.Data.values, mode='full')
t = (np.arange(len(x)) - len(x) / 2 + 0.5) / fs
x /= x.max()
fig, ax = plt.subplots()
ax.set_xlim(-ra, ra)
ax.set_ylim(0, 1)
ax.plot(t, x)
ax.set_title('Autocorrelation')
ax.grid(axis='x')
ax.set_xticks(np.linspace(-ra, ra, 2 * ra + 1))
plt.show()

acorr(df)

主な信号は 1/3 [Hz] であることがわかる。そのため、1/3 [Hz] でローパスフィルターをかける。

tmp

ローパスフィルターをかけ、極値の検出

ローパスフィルターをかけ、極値を検出できるようにする。

1/3 [Hz] でローパスフィルターをかけても正しく検出されない場合は、 周波数を下げていく。

tmp

fs = 10
lpf = 0.1
b, a = signal.butter(5, lpf / fs * 2, 'low')
df['Filter'] = signal.filtfilt(b, a, df.Data.values)
max_idx = signal.argrelmax(df['Filter'].values)
min_idx = signal.argrelmin(df['Filter'].values)

df['max_index'] = False
df.iloc[max_idx[0], 2] = True
df['min_index'] = False
df.iloc[min_idx[0], 3] = True

fig, ax = plt.subplots()
df.plot(ax=ax)
ax.set_xlim(['00:00:00', '00:00:30'])
ax.scatter(
df.loc[df['max_index'], ['Filter']].index,
df.loc[df['max_index'], ['Filter']],
color='tab:orange',
zorder=3)
ax.scatter(
df.loc[df['min_index'], ['Filter']].index,
df.loc[df['min_index'], ['Filter']],
color='tab:green',
zorder=3)
plt.show()

C 言語で 2 次元配列を扱う

· 約1分
ひかり
Main bloger

行数・列数、数値の入るメモリを構造体でまとめると扱いやすい。

#include <stdio.h>
#include <stdlib.h>

typedef struct {
float *data;
int col_size;
int row_size;
} Mat;

void MatInit(Mat *mat, int row_size, int col_size) {
mat->row_size = row_size;
mat->col_size = col_size;
mat->data = (float *)calloc(row_size * col_size, sizeof(float));
}

float *MatAt(Mat *mat, int i, int j) {
return mat->data + i * mat->col_size + j;
}

void MatFree(Mat *mat) { free(mat->data); }

int main(void) {
Mat mat;
MatInit(&mat, 30, 5); // 30 行 5 列 の行列を初期化
*MatAt(&mat, 0, 0) = 50; // 行 0 列 0 に 50 を代入
printf("%f\n", *MatAt(&mat, 0, 0)); // 行 0, 列 0 の数値を表示

MatFree(&mat);

return 0;
}

Visual Studio Code で Got bad result from install script. のエラーの対処

· 約1分
ひかり
Main bloger

vscode で ssh をしようとしたが、Got bad result from install script. というエラーが起き、接続できない。

何故かコマンドプロンプトも起動しない。

解決法

レジストリ エディターを開き、HKEY_CURRENT_USER\Software\Microsoft\Command Processor にある AutoRun の値を空にした。

NMF (HALS) の実装

· 約1分
ひかり
Main bloger
import numpy as np

X = np.array([[1, 1], [2, 1], [3, 1.2], [4, 1], [5, 0.8], [6, 1]])

n_components, n_samples, n_features, = (2,) + X.shape
W = np.random.uniform(size = (n_samples, n_components))
H = np.random.uniform(size = (n_components, n_features))

eps = 1e-4

# NMF
for i in range(100):
# update B
A = X.T.dot(W)
B = W.T.dot(W)
for j in range(n_components):
tmp = H[j, :] + A[:, j] - H.T.dot(B[:, j])
H[j, :] = np.maximum(tmp, eps)

# update A
C = X.dot(H.T)
D = H.dot(H.T)
for j in range(n_components):
tmp = W[:, j] * D[j, j] + C[:, j] - W.dot(D[:, j])
W[:, j] = np.maximum(tmp, eps)
norm = np.linalg.norm(W[:, j])
if norm > 0:
W[:, j] /= norm

print(W)
print(H)
print(W.dot(H))

WSL2 で DNS サーバーを設定する

· 約1分
ひかり
Main bloger

/etc/resolv.conf の自動生成の無効化

/etc/wsl.conf を以下のように編集する。

[network]
generateResolvConf = false

/etc/resolv.conf の作成

例えば、DNS サーバーが 1.1.1.1 のとき、/etc/resolv.conf は以下のように編集する。

nameserver 1.1.1.1

削除されないように

WSL2 を再起動すると /etc/resolv.conf が削除されるので、削除されないようにする。

sudo chattr +i /etc/resolv.conf

参考サイト

brew 環境下で nokogiri をインストールできないとき

· 約1分
ひかり
Main bloger

以下の二つのエラーが出た。

zlib is missing; necessary for building libxml2
xslt is missing. Please locate mkmf.log to investigate how it is failing.

解決法

  • libxslt, libxml2 をインストール
  • brew でインストールされている libxml2 のパスを指定
brew install libxslt libxml2
bundle config build.nokogiri --use-system-libraries --with-xml2-include=$(brew --prefix libxml2)/include/libxml2

参考サイト

Windows の OpenSSH で Permission denied が出る原因

· 約1分
ひかり
Main bloger
  • パスワードでのログインは可能 (ただし、設定で無効化している)
  • 公開鍵認証で Permission denied が出る

実際に localhost:22 に接続すると、

hikari@localhost: Permission denied (publickey,keyboard-interactive).

とエラーが出る。

image

原因

Administrators グループ、つまり「管理者ユーザー」はデフォルトで、C:\ProgramData\ssh\administrators_authorized_keys の公開鍵を 参照して認証しているようだ。

これを、$env:userprofile\.ssh\authorized_keys に変更する。

解決法

管理者権限で C:\ProgramData\ssh\sshd_config を開き、以下のように下の二行をコメントする。

image

- Match Group administrators
- AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
+ #Match Group administrators
+ # AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

保存が終わったら、サービスを再起動する。

Restart-Service sshd