Files
swiftGrammar/Pods/BlueECC/Sources/CryptorECC/ASN1.swift
2024-08-12 10:49:20 +08:00

93 lines
3.5 KiB
Swift

/**
* Copyright IBM Corporation 2019
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
import Foundation
// Private and public keys are stores in ASN1 format.
// The following code is used to parse the data and retrieve the required elements.
struct ASN1 {
indirect enum ASN1Element {
case seq(elements: [ASN1Element])
case integer(int: Int)
case bytes(data: Data)
case constructed(tag: Int, elem: ASN1Element)
case unknown
}
static func toASN1Element(data: Data) -> (ASN1Element, Int) {
guard data.count >= 2 else {
// format error
return (.unknown, data.count)
}
switch data[0] {
case 0x30: // sequence
let (length, lengthOfLength) = readLength(data: data.advanced(by: 1))
var result: [ASN1Element] = []
var subdata = data.advanced(by: 1 + lengthOfLength)
var alreadyRead = 0
while alreadyRead < length {
let (e, l) = toASN1Element(data: subdata)
result.append(e)
subdata = subdata.count > l ? subdata.advanced(by: l) : Data()
alreadyRead += l
}
return (.seq(elements: result), 1 + lengthOfLength + length)
case 0x02: // integer
let (length, lengthOfLength) = readLength(data: data.advanced(by: 1))
if length < 8 {
var result: Int = 0
let subdata = data.advanced(by: 1 + lengthOfLength)
// ignore negative case
for i in 0..<length {
result = 256 * result + Int(subdata[i])
}
return (.integer(int: result), 1 + lengthOfLength + length)
}
// number is too large to fit in Int; return the bytes
return (.bytes(data: data.subdata(in: (1 + lengthOfLength) ..< (1 + lengthOfLength + length))), 1 + lengthOfLength + length)
case let s where (s & 0xe0) == 0xa0: // constructed
let tag = Int(s & 0x1f)
let (length, lengthOfLength) = readLength(data: data.advanced(by: 1))
let subdata = data.advanced(by: 1 + lengthOfLength)
let (e, _) = toASN1Element(data: subdata)
return (.constructed(tag: tag, elem: e), 1 + lengthOfLength + length)
default: // octet string
let (length, lengthOfLength) = readLength(data: data.advanced(by: 1))
return (.bytes(data: data.subdata(in: (1 + lengthOfLength) ..< (1 + lengthOfLength + length))), 1 + lengthOfLength + length)
}
}
static private func readLength(data: Data) -> (Int, Int) {
if data[0] & 0x80 == 0x00 { // short form
return (Int(data[0]), 1)
} else {
let lenghOfLength = Int(data[0] & 0x7F)
var result: Int = 0
for i in 1..<(1 + lenghOfLength) {
result = 256 * result + Int(data[i])
}
return (result, 1 + lenghOfLength)
}
}
}