読者です 読者をやめる 読者になる 読者になる

餡子付゛録゛

ソフトウェア開発ツールの便利な使い方を紹介。

Rでパスワードを作る

R言語

最近はウェブサービスが乱立している事もあり、パスワードが漏洩する事件も良く聞くようになりました。この時に複数のサイトでパスワードが共通にしている人は、被害が他のサイトにも拡大していく可能性があります。
それを避けるために複数サイトで異なるパスワードを使うように推奨されていますが、人間がパスワードを生成すると何かの単語になりがちです。Appleのように厳しいパスワードを求めてくるサイトもあるので、自動で生成してみましょう。

#
# 'A', 'B', 'C' ... と言うパスワードに用いる文字のベクターを作る関数
# begin: 開始文字
# len: 長さ
# exception: 除外する文字
#
make_set <- function(begin, len, exception=c()){
  v <- strsplit(rawToChar(as.raw(0:(len-1) + as.integer(charToRaw(begin)))), "")[[1]]
  v[!v %in% exception]
}


#
# A〜Z、a〜z、0〜9のベクターを作る
# ただし紛らわしいIとl、Oと0は除外
#
chr_set_A <- make_set("A", 26, c("I", "O"))
chr_set_a <- make_set("a", 26, c("l"))
chr_set_0 <- make_set("0", 10, c("0"))
# 三つを合成する
chr_set <- c(chr_set_A, chr_set_a, chr_set_0)
# 乱数を初期化
# 注意:Seedの生成方法が分かるとパスワードを特定されやすくなるので、ある程度の長さの任意の数字(secret_code)を加えるなどした方が安全。
secret_code <- 192837465
set.seed(as.integer((1000*as.numeric(format(Sys.time(),"%y%j%H%M%OS3")) + secret_code) %% .Machine$integer.max))
#
# Apple IDを意識して、三種類の文字がないと脆弱パスワードと見なす関数
# clst: パスワードに使う文字のベクター
#
is_strong <- function(clst){
  if(!any(clst %in% chr_set_A)){
    return(FALSE)
  }
  if(!any(clst %in% chr_set_a)){
    return(FALSE)
  }
  if(!any(clst %in% chr_set_0)){
    return(FALSE)
  }
  # 三連続同一文字の禁止
  len <- length(clst)
  if(3 > len){
    return(FALSE)
  }
  for(i in 1:(len-2)){
    if(clst[i]==clst[i+1] & clst[i]==clst[i+2]){
      return(FALSE)
    }
  }
  TRUE
}


#
# 強度のあるパスワードを作る関数
# args: [パスワードの長さ#1],[パスワードの長さ#2]...
#
mkpasswd <- function(...){
  digit <- length(chr_set) # パスワードの各桁の文字種の数
  # Rらしく引数の数は不定
  len <- c(...)
  num <- length(len)
  # 戻り値を初期化しておく
  r <- character(num)
  for(i in 1:num){
    # 3以下のパラメーターは計算できないので、除外
    if(3>len[i]){
      r[i] <- NaN
      next
    }
    # 強度を満たすまで生成しなおす
    clst <- c()
    while(!is_strong(clst)){
      # +0.5がないと、最初の一文字の発生確率が半分になってしまう
      clst <- chr_set[round(runif(len[i], 0, digit) + 0.5)]
    }
    # collapse引数が無いとベクターは合体しない
    r[i] <- paste(clst, collapse="")
  }
  r
}


# 8文字のパスワードを作ってみる
sprintf("生成されたパスワード: %s", mkpasswd(8))

本当の問題は、どうやって大量のパスワードを管理するかなのですが、強度のあるパスワードを簡単に作る事ができます。