Skip to content

Instantly share code, notes, and snippets.

@d4r1091
Last active August 26, 2019 10:15
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 d4r1091/a0c9f841d2071d274155723e560aaae6 to your computer and use it in GitHub Desktop.
Save d4r1091/a0c9f841d2071d274155723e560aaae6 to your computer and use it in GitHub Desktop.
URandom OSX - Linux no dependencies
// Source: https://github.com/vapor-community/random
public protocol RandomProtocol {
/// Get a random array of Bytes
func bytes(count: Int) throws -> Bytes
}
// MARK: - Throwing getter methods
extension RandomProtocol {
/// Get a random Int8
public func makeInt8() throws -> Int8 {
return Int8(bitPattern: try makeUInt8())
}
/// Get a random UInt8
public func makeUInt8() throws -> UInt8 {
return try bytes(count: 1)[0]
}
/// Get a random Int16
public func makeInt16() throws -> Int16 {
return Int16(bitPattern: try makeUInt16())
}
/// Get a random UInt16
public func makeUInt16() throws -> UInt16 {
let random = try bytes(count: 2)
return UnsafeRawPointer(random)
.assumingMemoryBound(to: UInt16.self)
.pointee
}
/// Get a random Int32
public func makeInt32() throws -> Int32 {
return Int32(bitPattern: try makeUInt32())
}
/// Get a random UInt32
public func makeUInt32() throws -> UInt32 {
let random = try bytes(count: 4)
return UnsafeRawPointer(random)
.assumingMemoryBound(to: UInt32.self)
.pointee
}
/// Get a random Int64
public func makeInt64() throws -> Int64 {
return Int64(bitPattern: try makeUInt64())
}
/// Get a random UInt64
public func makeUInt64() throws -> UInt64 {
let random = try bytes(count: 8)
return UnsafeRawPointer(random)
.assumingMemoryBound(to: UInt64.self)
.pointee
}
/// Get a random Int
public func makeInt() throws -> Int {
return Int(bitPattern: try makeUInt())
}
/// Get a random UInt
public func makeUInt() throws -> UInt {
let random = try bytes(count: MemoryLayout<UInt>.size)
return UnsafeRawPointer(random)
.assumingMemoryBound(to: UInt.self)
.pointee
}
}
// Adapted to work with both Linux and OSX
// Source: https://github.com/vapor-community/random
#if os(Linux)
import Glibc
#else
import Darwin
#endif
public typealias Bytes = [UInt8]
public typealias Byte = UInt8
/// URandom represents a file connection to /dev/urandom on Unix systems.
/// /dev/urandom is a cryptographically secure random generator provided by the OS.
public final class URandom: RandomProtocol {
public enum Error: Swift.Error {
case open(Int32)
case read(Int32)
}
private let file: UnsafeMutablePointer<FILE>
/// Initialize URandom
public init(path: String) throws {
guard let file = fopen(path, "rb") else {
// The Random protocol doesn't allow init to fail, so we have to
// check whether /dev/urandom was successfully opened here
throw Error.open(errno)
}
self.file = file
}
deinit {
fclose(file)
}
private func read(numBytes: Int) throws -> [Int8] {
// Initialize an empty array with space for numBytes bytes
var bytes = [Int8](repeating: 0, count: numBytes)
guard fread(&bytes, 1, numBytes, file) == numBytes else {
// If the requested number of random bytes couldn't be read,
// we need to throw an error
throw Error.read(errno)
}
return bytes
}
/// Get a random array of Bytes
public func bytes(count: Int) throws -> Bytes {
return try read(numBytes: count).map({ Byte(bitPattern: $0) })
}
}
extension URandom {
public convenience init() throws {
try self.init(path: "/dev/urandom")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment