Skip to content

Instantly share code, notes, and snippets.

@mntone
Last active December 1, 2020 12:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mntone/ea5fb9909ce1a078959464629ebc7a9c to your computer and use it in GitHub Desktop.
Save mntone/ea5fb9909ce1a078959464629ebc7a9c to your computer and use it in GitHub Desktop.
何かの残骸。正しく動作しません。ただ,クラス実装は何かに流用できる可能性があります。🌟under MIT license
import CommonCrypto
import CryptoKit
import Foundation
protocol PinCodeFactory {
mutating func update(by timeStep: Int32)
mutating func update(by timeStep: Int32, at baseTime: Int32)
mutating func update(using counter: Int64)
mutating func getPincode(to digits: Int) -> Int32
}
extension PinCodeFactory {
mutating func update(by timeStep: Int32) {
update(by: timeStep, at: 0)
}
mutating func update(by timeStep: Int32, at baseTime: Int32) {
let x = (Date().timeIntervalSince1970 - Double(baseTime)) / Double(timeStep)
update(using: Int64(x))
}
}
func makePinCodeFactory(_ algorithm: OneTimePasswordAlgorithm, using key: String) -> PinCodeFactory {
if #available(iOS 13.0, macOS 10.15, watchOS 6.0, *) {
switch algorithm {
case .MD5:
return MD5PinCodeFactory(key)
case .SHA1:
return SHA1PinCodeFactory(key)
case .SHA256:
return SHA256PinCodeFactory(key)
case .SHA384:
return SHA384PinCodeFactory(key)
case .SHA512:
return SHA512PinCodeFactory(key)
}
} else {
switch algorithm {
case .MD5:
return MD5CompatibilityPinCodeFactory(key)
case .SHA1:
return SHA1CompatibilityPinCodeFactory(key)
case .SHA256:
return SHA256CompatibilityPinCodeFactory(key)
case .SHA384:
return SHA384CompatibilityPinCodeFactory(key)
case .SHA512:
return SHA512CompatibilityPinCodeFactory(key)
}
}
}
private let DIGITS_POWER: [Int32] = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000]
// ---
// iOS: 13.0-
// macOS: 10.15.x, 11.0-
// watchOS: 6.0-
// ---
@available(iOS 13.0, macOS 10.15, watchOS 6.0, *)
protocol PinCodeFactoryImplementation {
associatedtype H: HashFunction
var factory: HMAC<H> { get set }
init(_ key: SymmetricKey)
}
@available(iOS 13.0, macOS 10.15, watchOS 6.0, *)
extension PinCodeFactoryImplementation {
init(_ data: Data) {
let symetricKey = SymmetricKey(data: data)
self.init(symetricKey)
}
init(_ string: String) {
let data = string.data(using: .utf8)!
self.init(data)
}
mutating func update(using counter: Int64) {
factory.update(data: counter.bigEndian.toData())
}
func getPincode(to digits: Int) -> Int32 {
let hash = factory.finalize()
let binary = hash.withUnsafeBytes { hash -> Int32 in
let offset = Int(hash[hash.count - 1] & 0x0F)
var buffer = [UInt8](repeating: 0, count: 4)
return buffer.withUnsafeMutableBytes { p in
hash.copyBytes(to: p, from: offset..<offset + 4)
return Int32(bigEndian: p.load(as: Int32.self)) & 0x7FFFFFFF
}
}
if digits >= 10 {
return binary
} else {
return binary % DIGITS_POWER[digits]
}
}
}
@available(iOS 13.0, macOS 10.15, watchOS 6.0, *)
final class MD5PinCodeFactory: PinCodeFactory, PinCodeFactoryImplementation {
var factory: HMAC<Insecure.MD5>
init(_ key: SymmetricKey) {
self.factory = HMAC<Insecure.MD5>(key: key)
}
}
@available(iOS 13.0, macOS 10.15, watchOS 6.0, *)
final class SHA1PinCodeFactory: PinCodeFactory, PinCodeFactoryImplementation {
var factory: HMAC<Insecure.SHA1>
init(_ key: SymmetricKey) {
self.factory = HMAC<Insecure.SHA1>(key: key)
}
}
@available(iOS 13.0, macOS 10.15, watchOS 6.0, *)
final class SHA256PinCodeFactory: PinCodeFactory, PinCodeFactoryImplementation {
var factory: HMAC<SHA256>
init(_ key: SymmetricKey) {
self.factory = HMAC<SHA256>(key: key)
}
}
@available(iOS 13.0, macOS 10.15, watchOS 6.0, *)
final class SHA384PinCodeFactory: PinCodeFactory, PinCodeFactoryImplementation {
var factory: HMAC<SHA384>
init(_ key: SymmetricKey) {
self.factory = HMAC<SHA384>(key: key)
}
}
@available(iOS 13.0, macOS 10.15, watchOS 6.0, *)
final class SHA512PinCodeFactory: PinCodeFactory, PinCodeFactoryImplementation {
var factory: HMAC<SHA512>
init(_ key: SymmetricKey) {
self.factory = HMAC<SHA512>(key: key)
}
}
// ---
// iOS: -12.x
// macOS: -10.14.x
// watchOS: -5.x
// ---
@available(iOS, introduced: 2.0, deprecated: 13.0)
@available(macOS, introduced: 10.4, deprecated: 10.15)
@available(watchOS, deprecated: 6.0)
protocol PinCodeFactoryCompatibilityImplementation {
var context: CCHmacContext { get set }
var algorithm: CCHmacAlgorithm { get }
var length: Int { get }
init(_ data: Data)
}
@available(iOS, introduced: 2.0, deprecated: 13.0)
@available(macOS, introduced: 10.4, deprecated: 10.15)
@available(watchOS, deprecated: 6.0)
extension PinCodeFactoryCompatibilityImplementation {
init(_ string: String) {
let data = string.data(using: .utf8)!
self.init(data)
}
mutating func update(using counter: Int64) {
withUnsafeBytes(of: counter) {
CCHmacUpdate(&context, $0.baseAddress, MemoryLayout<Int64>.size)
}
}
mutating func getPincode(to digits: Int) -> Int32 {
var hash = Array<UInt8>(repeating: 0, count: length)
CCHmacFinal(&context, &hash)
let offset = Int(hash[length - 1] & 0x0F)
var buffer = [UInt8](repeating: 0, count: 4)
let binary = buffer.withUnsafeMutableBytes { p -> Int32 in
hash.copyBytes(to: p, from: offset..<offset + 4)
return Int32(bigEndian: p.load(as: Int32.self)) & 0x7FFFFFFF
}
if digits >= 10 {
return binary
} else {
return binary % DIGITS_POWER[digits]
}
}
}
@available(iOS, introduced: 2.0, deprecated: 13.0)
@available(macOS, introduced: 10.4, deprecated: 10.15)
@available(watchOS, deprecated: 6.0)
final class MD5CompatibilityPinCodeFactory: PinCodeFactory, PinCodeFactoryCompatibilityImplementation {
var context = CCHmacContext()
var algorithm: CCHmacAlgorithm { CCHmacAlgorithm(kCCHmacAlgMD5) }
var length: Int { Int(CC_MD5_DIGEST_LENGTH) }
init(_ data: Data) {
let ptr = data.withUnsafeBytes { $0.baseAddress! }
CCHmacInit(&context, algorithm, ptr, data.count)
}
}
@available(iOS, introduced: 2.0, deprecated: 13.0)
@available(macOS, introduced: 10.4, deprecated: 10.15)
@available(watchOS, deprecated: 6.0)
final class SHA1CompatibilityPinCodeFactory: PinCodeFactory, PinCodeFactoryCompatibilityImplementation {
var context = CCHmacContext()
var algorithm: CCHmacAlgorithm { CCHmacAlgorithm(kCCHmacAlgSHA1) }
var length: Int { Int(CC_SHA1_DIGEST_LENGTH) }
init(_ data: Data) {
let ptr = data.withUnsafeBytes { $0.baseAddress! }
CCHmacInit(&context, algorithm, ptr, data.count)
}
}
@available(iOS, introduced: 2.0, deprecated: 13.0)
@available(macOS, introduced: 10.4, deprecated: 10.15)
@available(watchOS, deprecated: 6.0)
final class SHA256CompatibilityPinCodeFactory: PinCodeFactory, PinCodeFactoryCompatibilityImplementation {
var context = CCHmacContext()
var algorithm: CCHmacAlgorithm { CCHmacAlgorithm(kCCHmacAlgSHA256) }
var length: Int { Int(CC_SHA256_DIGEST_LENGTH) }
init(_ data: Data) {
let ptr = data.withUnsafeBytes { $0.baseAddress! }
CCHmacInit(&context, algorithm, ptr, data.count)
}
}
@available(iOS, introduced: 2.0, deprecated: 13.0)
@available(macOS, introduced: 10.4, deprecated: 10.15)
@available(watchOS, deprecated: 6.0)
final class SHA384CompatibilityPinCodeFactory: PinCodeFactory, PinCodeFactoryCompatibilityImplementation {
var context = CCHmacContext()
var algorithm: CCHmacAlgorithm { CCHmacAlgorithm(kCCHmacAlgSHA384) }
var length: Int { Int(CC_SHA384_DIGEST_LENGTH) }
init(_ data: Data) {
let ptr = data.withUnsafeBytes { $0.baseAddress! }
CCHmacInit(&context, algorithm, ptr, data.count)
}
}
@available(iOS, introduced: 2.0, deprecated: 13.0)
@available(macOS, introduced: 10.4, deprecated: 10.15)
@available(watchOS, deprecated: 6.0)
final class SHA512CompatibilityPinCodeFactory: PinCodeFactory, PinCodeFactoryCompatibilityImplementation {
var context = CCHmacContext()
var algorithm: CCHmacAlgorithm { CCHmacAlgorithm(kCCHmacAlgSHA512) }
var length: Int { Int(CC_SHA512_DIGEST_LENGTH) }
init(_ data: Data) {
let ptr = data.withUnsafeBytes { $0.baseAddress! }
CCHmacInit(&context, algorithm, ptr, data.count)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment