Swift对象的安全内存 [英] Secure Memory For Swift Objects

查看:125
本文介绍了Swift对象的安全内存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am writing a swift application that requires handling private keys in memory. Because of the sensitivity of such objects, the keys need to be cleared (a.k.a. written to all zeros) when the object is deallocated, and the memory cannot be paged to disk (which is typically done using mlock()).

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

In Objective-C, you can provide a custom CFAllocator object, which allows you to use your own functions to allocate/deallocate/reallocate the memory used by an object.

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

So one solution is to just implement a "SecureData" object in objective-c, which internally creates an NSMutableData object using a custom CFAllocator (also in objective-c).

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

However, is there any way for me to provide my own custom memory allocation functions for a pure swift object (for example, a struct or a [UInt8])? Or is there a better, "proper" way to implement secure memory like this in swift?

推荐答案

如果你想完全控制你自己分配的一个记忆区域,你可以使用 UnsafePointer 和co:

If you want complete control over a region of memory you allocate yourself, you can use UnsafePointer and 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传递的内存。

You can also have UnsafePointer point to other memory, such as memory you’re handed by some C API.

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

UnsafePointer can be passed into C functions that take a pointer to a contiguous block of memory. So for your purposes, you could then pass this pointer into a function like 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)

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

You can even hold your own custom types:

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)

然而请注意,如果对类,甚至数组或字符串(或包含它们的结构)执行此操作,所有你将留在你的记忆中的是指向这些o的其他记忆对象分配和拥有。如果这对你很重要(比如你在这个记忆中做了一些特别的事情,比如保护它,在你的例子中),这可能不是你想要的。

However be aware if doing this with classes, or even arrays or strings (or a struct that contains them), that all you will be holding in your memory is pointers to other memory that these objects allocate and own. If this matters to you (i.e. you are doing something special to this memory such as securing it, in your example), this is probably not what you want.

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

So either you need to use fixed-size objects, or make further use of UnsafePointer to hold pointers to more memory regions. If they don't need to dynamically resize, then just a single allocation of an unsafe pointer, possibly wrapped in a UnsafeBufferPointer for a collection interface, could do it.

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

If you need more dynamic behavior, below is a very bare-bones implementation of a collection that can resize as necessary, that could be enhanced to cover specialty memory-handling logic:

// 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 加上可分配的下标):

To cover the requirements of MutableCollectionType (i.e. CollectionType plus assignable subscript):

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 ,以允许动态增长:

And ExtensibleCollectionType, to allow for dynamic growth:

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)
        }
    }
}

这篇关于Swift对象的安全内存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆