LoginSignup
2
3

More than 5 years have passed since last update.

Google Authenticator in Swift

Last updated at Posted at 2015-09-27

 再現してたら1週間かかったのは秘密。

 なんかすごく時間がないので、詳しいことは来週加筆します。
 本当はもっとマトモなエクステンションにしたかったんです… しかし時間が… ウグッ

 挙動確認するときは認証アプリに手動でアカウント登録してくだしあ

bridging-header.h
#import <CommonCrypto/CommonHMAC.h>
main.swift
import Cocoa

extension NSDate {
    static func google2FA(key: String) -> String {
        func base32decode(k: String) -> [UInt8] {
            func decode(c: CChar) -> UInt8? {
                switch c {
                case 50...55:
                    return UInt8(c - 24)
                case 65...90:
                    return UInt8(c - 65)
                default:
                    return nil
                }
            }
            func convert(raw: ArraySlice<CChar>, result: [UInt8]) -> [UInt8] {
                if let first = raw.first.flatMap(decode) {
                    return convert(raw.dropFirst(), result: result + [first])
                } else {
                    return result
                }
            }
            let nums = k.uppercaseString.cStringUsingEncoding(NSASCIIStringEncoding)
                .map(ArraySlice.init).map { convert($0, result: []) } ?? []
            var bs = [UInt8]()
            var buffer = 0
            var length = 0
            for c in nums {
                buffer = buffer << 5 | numericCast(c)
                length += 5
                if (length >= 8) {
                    bs.append(numericCast(buffer >> (length - 8)))
                    buffer -= (numericCast(bs.last!) << (length - 8))
                    length -= 8
                }
            }
            return bs
        }
        let secret = base32decode(key)

        var time = CFSwapInt64HostToBig(UInt64(NSDate().timeIntervalSince1970) / 30)
        var hash = [UInt8](count: numericCast(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
        CCHmac(numericCast(kCCHmacAlgSHA1), secret, secret.count, &time, sizeof(UInt64), &hash)

        let offset = Int(hash.last!) & 0xf
        let truncated = hash[offset...offset + 3]

        var t = 0
        for n in truncated {
            t = (t << 8) | numericCast(n)
        }
        return String(format: "%06d", (t & (0x7fffffff) ) % 1000000)
    }
}

// 使い方
print(NSDate.google2FA("aaaaaaaaaaaaaaaa"))
2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3