快速对象的安全内存

时间:2014-12-31 04:06:37

标签: ios macos security swift memory-management

我正在编写一个需要在内存中处理私钥的快速应用程序。由于这些对象的敏感性,当对象被释放时,需要清除密钥(例如写入全零),并且内存不能被分页到磁盘(通常使用mlock()完成)。

在Objective-C中,您可以提供一个自定义CFAllocator对象,它允许您使用自己的函数来分配/释放/重新分配对象使用的内存。

所以一个解决方案就是实现一个" SecureData" objective-c中的对象,它使用自定义CFAllocator在内部创建NSMutableData对象(也在objective-c中)。

但是,有没有办法为纯swift对象提供自己的自定义内存分配函数(例如,struct或[UInt8])?或者有更好的,适当的"如何在swift中实现这样的安全内存?

2 个答案:

答案 0 :(得分:33)

如果您希望完全控制自己分配的内存区域,可以使用UnsafePointer和co:

// allocate enough memory for ten Ints
var ump = UnsafeMutablePointer<Int>.alloc(10)
// memory is in an uninitialized raw state

// initialize that memory with Int objects
// (here, from a collection)
ump.initializeFrom(reverse(0..<10))

// memory property gives you access to the underlying value
ump.memory // 9

// UnsafeMutablePointer acts like an IndexType
ump.successor().memory // 8
// and it has a subscript, but it's not a CollectionType
ump[3] // = 6

// wrap it in an UnsafeMutableBufferPointer to treat it
// like a collection (or UnsafeBufferPointer if you don't
// need to be able to alter the values)
let col = UnsafeMutableBufferPointer(start: ump, count: 10)
col[3] = 99
println(",".join(map(col,toString)))
// prints 9,8,7,99,5,4,3,2,1,0

ump.destroy(10)
// now the allocated memory is back in a raw state
// you could re-allocate it...
ump.initializeFrom(0..<10)
ump.destroy(10)

// when you're done, deallocate the memory
ump.dealloc(10)

您还可以UnsafePointer指向其他内存,例如您通过某些C API传递的内存。

UnsafePointer可以传递给C函数,这些函数接受指向连续内存块的指针。因此,为了您的目的,您可以将此指针传递给类似mlock

的函数
let count = 10
let ump = UnsafeMutablePointer.allocate<Int>(count)
mlock(ump, UInt(sizeof(Int) * count))
// initialize, use, and destroy the memory
munlock(ump, UInt(sizeof(Int) * count))
ump.dealloc(count)

您甚至可以拥有自己的自定义类型:

struct MyStruct {
    let a: Int
    let b: Int
}

var pointerToStruct = UnsafeMutablePointer<MyStruct>.alloc(1)
pointerToStruct.initialize(MyStruct(a: 1, b: 2))
pointerToStruct.memory.b  // 2
pointerToStruct.destroy()
pointerToStruct.dealloc(1)

然而要知道如果对类,甚至数组或字符串(或包含它们的结构)这样做,你将在内存中保存的所有内容都指向这些对象的其他内存分配和拥有。如果这对你很重要(也就是你在这个记忆中做了一些特别的事情,比如保护它,在你的例子中),这可能不是你想要的。

因此,您需要使用固定大小的对象,或者进一步使用UnsafePointer来保存指向更多内存区域的指针。如果它们不需要动态调整大小,那么只需一个不安全指针的分配(可能包含在集合接口的UnsafeBufferPointer中)就可以完成。

如果您需要更多动态行为,下面是一个非常简单的集合实现,可以根据需要调整大小,可以增强以涵盖专业内存处理逻辑:

// Note this is a class not a struct, so it does NOT have value semantics,
// changing a copy changes all copies.
public class UnsafeCollection<T> {
    private var _len: Int = 0
    private var _buflen: Int = 0
    private var _buf: UnsafeMutablePointer<T> = nil

    public func removeAll(keepCapacity: Bool = false) {
        _buf.destroy(_len)
        _len = 0
        if !keepCapacity {
            _buf.dealloc(_buflen)
            _buflen = 0
            _buf = nil
        }
    }

    public required init() { }
    deinit { self.removeAll(keepCapacity: false) }

    public var count: Int { return _len }
    public var isEmpty: Bool { return _len == 0 }
}

要涵盖MutableCollectionType的要求(即CollectionType加上可分配的下标):

extension UnsafeCollection: MutableCollectionType {
    typealias Index = Int
    public var startIndex: Int { return 0 }
    public var endIndex: Int { return _len }

    public subscript(idx: Int) -> T {
        get {
            precondition(idx < _len)
            return _buf[idx]
        }
        set(newElement) {
            precondition(idx < _len)
            let ptr = _buf.advancedBy(idx)
            ptr.destroy()
            ptr.initialize(newElement)
        }
    }

    typealias Generator = IndexingGenerator<UnsafeCollection>
    public func generate() -> Generator {
        return Generator(self)
    }
}

ExtensibleCollectionType,以实现动态增长:

extension UnsafeCollection: ExtensibleCollectionType {
    public func reserveCapacity(n: Index.Distance) {
        if n > _buflen {
            let newBuf = UnsafeMutablePointer<T>.alloc(n)
            newBuf.moveInitializeBackwardFrom(_buf, count: _len)
            _buf.dealloc(_buflen)
            _buf = newBuf
            _buflen = n
        }
    }

    public func append(x: T) {
        if _len == _buflen {
            reserveCapacity(Int(Double(_len) * 1.6) + 1)
        }
        _buf.advancedBy(_len++).initialize(x)
    }

    public func extend<S: SequenceType where S.Generator.Element == T>
      (newElements: S) {
        var g = newElements.generate()
        while let x: T = g.next() {
            self.append(x)
        }
    }
}

答案 1 :(得分:2)

我知道这个问题很旧,但是对于那些登陆这里的人来说有些问题:从iOS 10开始,您可以使用Secure Enclave安全地存储私钥。它的工作方式是,所有需要解密的操作都在Secure Enclave内部执行,因此您不必担心类的运行时挂钩或内存泄漏。

在这里看看:https://developer.apple.com/documentation/security/certificate_key_and_trust_services/keys/storing_keys_in_the_secure_enclave