Skip to content

Commit f5d81bc

Browse files
fix: added new implementation of randomBytes and deprecated old one
1 parent 7f05f01 commit f5d81bc

File tree

1 file changed

+39
-15
lines changed

1 file changed

+39
-15
lines changed

Sources/Web3Core/Utility/Data+Extension.swift

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,27 +41,51 @@ extension Data {
4141
}
4242
}
4343

44+
@available(*, deprecated, message: "Please, use throwing `randomBytes(count)` function instead to get information instead of `nil` value on why the function call failed.")
45+
/// Runs `SecRandomCopyBytes` for Apple platforms and `openssl rand -hex` for other platforms
46+
/// to generate cryptographically secure random bytes.
47+
/// - Parameter count: how many bytes to generate. Value below or equal to 0 will return `nil`.
48+
/// - Returns: random bytes or `nil`.
4449
public static func randomBytes(length: Int) -> Data? {
45-
#if os(Linux)
46-
// return Data(URandom().bytes(count: length))
47-
return try? Data.random(length: length)
48-
#else
49-
for _ in 0...1024 {
50-
var data = Data(repeating: 0, count: length)
51-
let result = data.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) -> Int32? in
52-
if let bodyAddress = body.baseAddress, body.count > 0 {
50+
try? randomBytes(count: length)
51+
}
52+
53+
/// Runs `SecRandomCopyBytes` for Apple platforms and `openssl rand -hex` for other platforms
54+
/// to generate cryptographically secure random bytes.
55+
/// - Parameter count: how many bytes to generate. Value below or equal to 0 will throw an error.
56+
/// - Parameter useOpenSSL: **has no effect on Linux and Windows**. When set to `true` forces the use of external executable `openssl`. It's your responsibility to make sure openssl is installed on this machine. By default set to `false`. To install follow [the official guide](https://www.openssl.org/source/ ).
57+
/// - Returns: random bytes or throws an error,
58+
public static func randomBytes(count: Int, useOpenSSL: Bool = true) throws -> Data {
59+
guard count > 0 else { throw Web3Error.valueError(desc: "Cannot generate \(count) random bytes.") }
60+
61+
#if !(os(Linux) || os(Windows))
62+
if !useOpenSSL {
63+
for _ in 0...1024 {
64+
var data = Data(repeating: 0, count: count)
65+
let result = try data.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) -> Int32? in
66+
guard let bodyAddress = body.baseAddress, body.count == count else {
67+
throw Web3Error.processingError(desc: "Address of the buffer is nil (\(body.baseAddress == nil)) or the count of bytes in the buffer is not equal to the count requested by the user (\(body.count < count)).")
68+
}
69+
5370
let pointer = bodyAddress.assumingMemoryBound(to: UInt8.self)
54-
return SecRandomCopyBytes(kSecRandomDefault, length, pointer)
55-
} else {
56-
return nil
71+
return SecRandomCopyBytes(kSecRandomDefault, count, pointer)
72+
}
73+
if let notNilResult = result, notNilResult == errSecSuccess {
74+
return data
5775
}
58-
}
59-
if let notNilResult = result, notNilResult == errSecSuccess {
60-
return data
6176
}
6277
}
63-
return nil
6478
#endif
79+
let randomBytesHex = try ShellCommandExecutor().run(commandName: "openssl rand -hex \(count)")
80+
guard let bytes = Data.fromHex(randomBytesHex) else {
81+
throw Web3Error.processingError(desc: "Random bytes generated by the openssl are in an invalid hex representation: \(randomBytesHex)")
82+
}
83+
84+
guard bytes.count == count else {
85+
throw Web3Error.processingError(desc: "Count of generated by the openssl random bytes is not equal to the count requested by the user: expected \(count), given \(bytes.count).")
86+
}
87+
88+
return bytes
6589
}
6690

6791
public func bitsInRange(_ startingBit: Int, _ length: Int) -> UInt64? { // return max of 8 bytes for simplicity, non-public

0 commit comments

Comments
 (0)