An experimental share extension to send files and too much refactoring

closes #4
This commit is contained in:
Grishka
2023-09-26 03:22:23 +03:00
parent 22a2fff54b
commit 8f0eccd7b6
39 changed files with 2158 additions and 235 deletions

View File

@@ -0,0 +1,47 @@
//
// Data+URLSafeBase64.swift
// NearDrop
//
// Created by Grishka on 08.04.2023.
//
import Foundation
import CoreFoundation
extension Data{
func urlSafeBase64EncodedString() -> String {
return String(base64EncodedString().replacingOccurrences(of: "=", with: "").map {
if $0=="/"{
return "_"
} else if $0=="+" {
return "-"
} else {
return $0
}
})
}
static func randomData(length: Int) -> Data{
var data=Data(count: length)
data.withUnsafeMutableBytes {
guard 0 == SecRandomCopyBytes(kSecRandomDefault, length, $0.baseAddress!) else { fatalError() }
}
return data
}
static func dataFromUrlSafeBase64(_ str:String)->Data?{
var regularB64=String(str.map{
if $0=="_"{
return "/"
}else if $0=="-"{
return "+"
}else{
return $0
}
})
while (regularB64.count%4) != 0{
regularB64=regularB64+"="
}
return Data(base64Encoded: regularB64, options: .ignoreUnknownCharacters)
}
}

View File

@@ -0,0 +1,3 @@
#!/bin/bash
ls ProtobufSource | xargs protoc --swift_out=Protobuf --proto_path=ProtobufSource

View File

@@ -0,0 +1,353 @@
//
// InboundNearbyConnection.swift
// NearDrop
//
// Created by Grishka on 08.04.2023.
//
import Foundation
import Network
import CryptoKit
import CommonCrypto
import System
import SwiftECC
import BigInt
class InboundNearbyConnection: NearbyConnection{
private var currentState:State = .initial
public var delegate:InboundNearbyConnectionDelegate?
private var cipherCommitment:Data?
enum State{
case initial, receivedConnectionRequest, sentUkeyServerInit, receivedUkeyClientFinish, sentConnectionResponse, sentPairedKeyResult, receivedPairedKeyResult, waitingForUserConsent, receivingFiles, disconnected
}
override init(connection: NWConnection, id:String) {
super.init(connection: connection, id: id)
}
override func handleConnectionClosure() {
super.handleConnectionClosure()
currentState = .disconnected
do{
try deletePartiallyReceivedFiles()
}catch{
print("Error deleting partially received files: \(error)")
}
DispatchQueue.main.async {
self.delegate?.connectionWasTerminated(connection: self, error: self.lastError)
}
}
override internal func processReceivedFrame(frameData:Data){
do{
switch currentState {
case .initial:
let frame=try Location_Nearby_Connections_OfflineFrame(serializedData: frameData)
try processConnectionRequestFrame(frame)
case .receivedConnectionRequest:
let msg=try Securegcm_Ukey2Message(serializedData: frameData)
ukeyClientInitMsgData=frameData
try processUkey2ClientInit(msg)
case .sentUkeyServerInit:
let msg=try Securegcm_Ukey2Message(serializedData: frameData)
try processUkey2ClientFinish(msg, raw: frameData)
case .receivedUkeyClientFinish:
let frame=try Location_Nearby_Connections_OfflineFrame(serializedData: frameData)
try processConnectionResponseFrame(frame)
default:
let smsg=try Securemessage_SecureMessage(serializedData: frameData)
try decryptAndProcessReceivedSecureMessage(smsg)
}
}catch{
lastError=error
print("Deserialization error: \(error) in state \(currentState)")
#if !DEBUG
protocolError()
#endif
}
}
override internal func processTransferSetupFrame(_ frame:Sharing_Nearby_Frame) throws{
if frame.hasV1 && frame.v1.hasType, case .cancel = frame.v1.type {
print("Transfer canceled")
try sendDisconnectionAndDisconnect()
return
}
switch currentState{
case .sentConnectionResponse:
try processPairedKeyEncryptionFrame(frame)
case .sentPairedKeyResult:
try processPairedKeyResultFrame(frame)
case .receivedPairedKeyResult:
try processIntroductionFrame(frame)
default:
print("Unexpected connection state in processTransferSetupFrame: \(currentState)")
print(frame)
}
}
override func isServer() -> Bool {
return true
}
override func processFileChunk(frame: Location_Nearby_Connections_PayloadTransferFrame) throws{
let id=frame.payloadHeader.id
guard let fileInfo=transferredFiles[id] else { throw NearbyError.protocolError("File payload ID \(id) is not known") }
let currentOffset=fileInfo.bytesTransferred
guard frame.payloadChunk.offset==currentOffset else { throw NearbyError.protocolError("Invalid offset into file \(frame.payloadChunk.offset), expected \(currentOffset)") }
guard currentOffset+Int64(frame.payloadChunk.body.count)<=fileInfo.meta.size else { throw NearbyError.protocolError("Transferred file size exceeds previously specified value") }
if frame.payloadChunk.body.count>0{
try fileInfo.fileHandle?.write(contentsOf: frame.payloadChunk.body)
transferredFiles[id]!.bytesTransferred+=Int64(frame.payloadChunk.body.count)
fileInfo.progress?.completedUnitCount=transferredFiles[id]!.bytesTransferred
}else if (frame.payloadChunk.flags & 1)==1{
try fileInfo.fileHandle?.close()
transferredFiles[id]!.fileHandle=nil
fileInfo.progress?.unpublish()
transferredFiles.removeValue(forKey: id)
if transferredFiles.isEmpty{
try sendDisconnectionAndDisconnect()
}
}
}
private func processConnectionRequestFrame(_ frame:Location_Nearby_Connections_OfflineFrame) throws{
guard frame.hasV1 && frame.v1.hasConnectionRequest && frame.v1.connectionRequest.hasEndpointInfo else { throw NearbyError.requiredFieldMissing }
guard case .connectionRequest = frame.v1.type else { throw NearbyError.protocolError("Unexpected frame type \(frame.v1.type)") }
let endpointInfo=frame.v1.connectionRequest.endpointInfo
guard endpointInfo.count>17 else { throw NearbyError.protocolError("Endpoint info too short") }
let deviceNameLength=Int(endpointInfo[17])
guard endpointInfo.count>=deviceNameLength+18 else { throw NearbyError.protocolError("Endpoint info too short to contain the device name") }
guard let deviceName=String(data: endpointInfo[18..<(18+deviceNameLength)], encoding: .utf8) else { throw NearbyError.protocolError("Device name is not valid UTF-8") }
let rawDeviceType:Int=Int(endpointInfo[0] & 7) >> 1
remoteDeviceInfo=RemoteDeviceInfo(name: deviceName, type: RemoteDeviceInfo.DeviceType.fromRawValue(value: rawDeviceType))
currentState = .receivedConnectionRequest
}
private func processUkey2ClientInit(_ msg:Securegcm_Ukey2Message) throws{
guard msg.hasMessageType, msg.hasMessageData else { throw NearbyError.requiredFieldMissing }
guard case .clientInit = msg.messageType else{
sendUkey2Alert(type: .badMessageType)
throw NearbyError.ukey2
}
let clientInit:Securegcm_Ukey2ClientInit
do{
clientInit=try Securegcm_Ukey2ClientInit(serializedData: msg.messageData)
}catch{
sendUkey2Alert(type: .badMessageData)
throw NearbyError.ukey2
}
guard clientInit.version==1 else{
sendUkey2Alert(type: .badVersion)
throw NearbyError.ukey2
}
guard clientInit.random.count==32 else{
sendUkey2Alert(type: .badRandom)
throw NearbyError.ukey2
}
var found=false
for commitment in clientInit.cipherCommitments{
if case .p256Sha512 = commitment.handshakeCipher{
found=true
cipherCommitment=commitment.commitment
break
}
}
guard found else{
sendUkey2Alert(type: .badHandshakeCipher)
throw NearbyError.ukey2
}
guard clientInit.nextProtocol=="AES_256_CBC-HMAC_SHA256" else{
sendUkey2Alert(type: .badNextProtocol)
throw NearbyError.ukey2
}
let domain=Domain.instance(curve: .EC256r1)
let (pubKey, privKey)=domain.makeKeyPair()
publicKey=pubKey
privateKey=privKey
var serverInit=Securegcm_Ukey2ServerInit()
serverInit.version=1
serverInit.random=Data.randomData(length: 32)
serverInit.handshakeCipher = .p256Sha512
var pkey=Securemessage_GenericPublicKey()
pkey.type = .ecP256
pkey.ecP256PublicKey=Securemessage_EcP256PublicKey()
pkey.ecP256PublicKey.x=Data(pubKey.w.x.asSignedBytes())
pkey.ecP256PublicKey.y=Data(pubKey.w.y.asSignedBytes())
serverInit.publicKey=try pkey.serializedData()
var serverInitMsg=Securegcm_Ukey2Message()
serverInitMsg.messageType = .serverInit
serverInitMsg.messageData=try serverInit.serializedData()
let serverInitData=try serverInitMsg.serializedData()
ukeyServerInitMsgData=serverInitData
sendFrameAsync(serverInitData)
currentState = .sentUkeyServerInit
}
private func processUkey2ClientFinish(_ msg:Securegcm_Ukey2Message, raw:Data) throws{
guard msg.hasMessageType, msg.hasMessageData else { throw NearbyError.requiredFieldMissing }
guard case .clientFinish = msg.messageType else { throw NearbyError.ukey2 }
var sha=SHA512()
sha.update(data: raw)
guard cipherCommitment==Data(sha.finalize()) else { throw NearbyError.ukey2 }
let clientFinish=try Securegcm_Ukey2ClientFinished(serializedData: msg.messageData)
guard clientFinish.hasPublicKey else {throw NearbyError.requiredFieldMissing }
let clientKey=try Securemessage_GenericPublicKey(serializedData: clientFinish.publicKey)
try finalizeKeyExchange(peerKey: clientKey)
currentState = .receivedUkeyClientFinish
}
private func processConnectionResponseFrame(_ frame:Location_Nearby_Connections_OfflineFrame) throws{
guard frame.hasV1, frame.v1.hasType else { throw NearbyError.requiredFieldMissing }
if case .connectionResponse = frame.v1.type {
var resp=Location_Nearby_Connections_OfflineFrame()
resp.version = .v1
resp.v1=Location_Nearby_Connections_V1Frame()
resp.v1.type = .connectionResponse
resp.v1.connectionResponse=Location_Nearby_Connections_ConnectionResponseFrame()
resp.v1.connectionResponse.response = .accept
resp.v1.connectionResponse.status=0
resp.v1.connectionResponse.osInfo=Location_Nearby_Connections_OsInfo()
resp.v1.connectionResponse.osInfo.type = .apple
sendFrameAsync(try resp.serializedData())
encryptionDone=true
var pairedEncryption=Sharing_Nearby_Frame()
pairedEncryption.version = .v1
pairedEncryption.v1=Sharing_Nearby_V1Frame()
pairedEncryption.v1.type = .pairedKeyEncryption
pairedEncryption.v1.pairedKeyEncryption=Sharing_Nearby_PairedKeyEncryptionFrame()
// Presumably used for all the phone number stuff that no one needs anyway
pairedEncryption.v1.pairedKeyEncryption.secretIDHash=Data.randomData(length: 6)
pairedEncryption.v1.pairedKeyEncryption.signedData=Data.randomData(length: 72)
try sendTransferSetupFrame(pairedEncryption)
currentState = .sentConnectionResponse
} else {
print("Unhandled offline frame plaintext: \(frame)")
}
}
private func processPairedKeyEncryptionFrame(_ frame:Sharing_Nearby_Frame) throws{
guard frame.hasV1, frame.v1.hasPairedKeyEncryption else { throw NearbyError.requiredFieldMissing }
var pairedResult=Sharing_Nearby_Frame()
pairedResult.version = .v1
pairedResult.v1=Sharing_Nearby_V1Frame()
pairedResult.v1.type = .pairedKeyResult
pairedResult.v1.pairedKeyResult=Sharing_Nearby_PairedKeyResultFrame()
pairedResult.v1.pairedKeyResult.status = .unable
try sendTransferSetupFrame(pairedResult)
currentState = .sentPairedKeyResult
}
private func processPairedKeyResultFrame(_ frame:Sharing_Nearby_Frame) throws{
guard frame.hasV1, frame.v1.hasPairedKeyResult else { throw NearbyError.requiredFieldMissing }
currentState = .receivedPairedKeyResult
}
private func processIntroductionFrame(_ frame:Sharing_Nearby_Frame) throws{
guard frame.hasV1, frame.v1.hasIntroduction else { throw NearbyError.requiredFieldMissing }
currentState = .waitingForUserConsent
let downloadsDirectory=(try FileManager.default.url(for: .downloadsDirectory, in: .userDomainMask, appropriateFor: nil, create: true)).resolvingSymlinksInPath()
for file in frame.v1.introduction.fileMetadata{
var dest=downloadsDirectory.appendingPathComponent(file.name)
if FileManager.default.fileExists(atPath: dest.path){
var counter=1
var path:String
let ext=dest.pathExtension
let baseUrl=dest.deletingPathExtension()
repeat{
path="\(baseUrl.path) (\(counter))"
if !ext.isEmpty{
path+=".\(ext)"
}
counter+=1
}while FileManager.default.fileExists(atPath: path)
dest=URL(fileURLWithPath: path)
}
let info=InternalFileInfo(meta: FileMetadata(name: file.name, size: file.size, mimeType: file.mimeType),
payloadID: file.payloadID,
destinationURL: dest)
transferredFiles[file.payloadID]=info
}
let metadata=TransferMetadata(files: transferredFiles.map({$0.value.meta}), id: id, pinCode: pinCode)
DispatchQueue.main.async {
self.delegate?.obtainUserConsent(for: metadata, from: self.remoteDeviceInfo!, connection: self)
}
}
func submitUserConsent(accepted:Bool){
DispatchQueue.global(qos: .utility).async {
if accepted{
self.acceptTransfer()
}else{
self.rejectTransfer()
}
}
}
private func acceptTransfer(){
do{
for (id, file) in transferredFiles{
FileManager.default.createFile(atPath: file.destinationURL.path, contents: nil)
let handle=try FileHandle(forWritingTo: file.destinationURL)
transferredFiles[id]!.fileHandle=handle
let progress=Progress()
progress.fileURL=file.destinationURL
progress.totalUnitCount=file.meta.size
progress.kind = .file
progress.isPausable=false
progress.publish()
transferredFiles[id]!.progress=progress
transferredFiles[id]!.created=true
}
var frame=Sharing_Nearby_Frame()
frame.version = .v1
frame.v1.type = .response
frame.v1.connectionResponse.status = .accept
currentState = .receivingFiles
try sendTransferSetupFrame(frame)
}catch{
print("Error \(error)")
protocolError()
}
}
private func rejectTransfer(){
var frame=Sharing_Nearby_Frame()
frame.version = .v1
frame.v1.type = .response
frame.v1.connectionResponse.status = .reject
do{
try sendTransferSetupFrame(frame)
try sendDisconnectionAndDisconnect()
}catch{
print("Error \(error)")
protocolError()
}
}
private func deletePartiallyReceivedFiles() throws{
for (_, file) in transferredFiles{
guard file.created else { continue }
try FileManager.default.removeItem(at: file.destinationURL)
}
}
}
protocol InboundNearbyConnectionDelegate{
func obtainUserConsent(for transfer:TransferMetadata, from device:RemoteDeviceInfo, connection:InboundNearbyConnection)
func connectionWasTerminated(connection:InboundNearbyConnection, error:Error?)
}

View File

@@ -0,0 +1,426 @@
//
// NearbyConnection.swift
// NearDrop
//
// Created by Grishka on 09.04.2023.
//
import Foundation
import Network
import CommonCrypto
import CryptoKit
import System
import SwiftECC
import BigInt
class NearbyConnection{
internal static let SANE_FRAME_LENGTH=5*1024*1024
private static let dispatchQueue=DispatchQueue(label: "me.grishka.NearDrop.queue", qos: .utility) // FIFO (non-concurrent) queue to avoid those exciting concurrency bugs
internal let connection:NWConnection
internal var remoteDeviceInfo:RemoteDeviceInfo?
private var payloadBuffers:[Int64:NSMutableData]=[:]
internal var encryptionDone:Bool=false
internal var transferredFiles:[Int64:InternalFileInfo]=[:]
public let id:String
internal var lastError:Error?
private var connectionClosed:Bool=false
// UKEY2-related state
internal var publicKey:ECPublicKey?
internal var privateKey:ECPrivateKey?
internal var ukeyClientInitMsgData:Data?
internal var ukeyServerInitMsgData:Data?
// SecureMessage encryption keys
internal var decryptKey:[UInt8]?
internal var encryptKey:[UInt8]?
internal var recvHmacKey:SymmetricKey?
internal var sendHmacKey:SymmetricKey?
// SecureMessage sequence numbers
private var serverSeq:Int32=0
private var clientSeq:Int32=0
private(set) var pinCode:String?
init(connection:NWConnection, id:String) {
self.connection=connection
self.id=id
}
func start(){
connection.stateUpdateHandler={state in
if case .ready = state {
self.connectionReady()
self.receiveFrameAsync()
} else if case .failed(let err) = state {
self.lastError=err
print("Error opening socket: \(err)")
self.handleConnectionClosure()
}
}
//connection.start(queue: .global(qos: .utility))
connection.start(queue: NearbyConnection.dispatchQueue)
}
func connectionReady(){}
internal func handleConnectionClosure(){
print("Connection closed")
}
internal func protocolError(){
disconnect()
}
internal func processReceivedFrame(frameData:Data){
fatalError()
}
internal func processTransferSetupFrame(_ frame:Sharing_Nearby_Frame) throws{
fatalError()
}
internal func isServer() -> Bool{
fatalError()
}
internal func processFileChunk(frame:Location_Nearby_Connections_PayloadTransferFrame) throws{
protocolError()
}
private func receiveFrameAsync(){
connection.receive(minimumIncompleteLength: 4, maximumLength: 4) { content, contentContext, isComplete, error in
if self.connectionClosed{
return
}
if isComplete{
self.handleConnectionClosure()
return
}
if !(error==nil){
self.lastError=error
self.protocolError()
return
}
guard let content=content else {
assertionFailure()
return
}
let frameLength:UInt32=UInt32(content[0]) << 24 | UInt32(content[1]) << 16 | UInt32(content[2]) << 8 | UInt32(content[3])
guard frameLength<NearbyConnection.SANE_FRAME_LENGTH else {
self.lastError=NearbyError.protocolError("Unexpected packet length")
self.protocolError()
return
}
self.receiveFrameAsync(length: frameLength)
}
}
private func receiveFrameAsync(length:UInt32){
connection.receive(minimumIncompleteLength: Int(length), maximumLength: Int(length)) { content, contentContext, isComplete, error in
if self.connectionClosed{
return
}
if isComplete{
self.handleConnectionClosure()
return
}
guard let content=content else {
self.protocolError()
return
}
self.processReceivedFrame(frameData: content)
self.receiveFrameAsync()
}
}
internal func sendFrameAsync(_ frame:Data, completion:(()->Void)?=nil){
if connectionClosed{
return
}
var lengthPrefixedData=Data(capacity: frame.count+4)
let length:Int=frame.count
lengthPrefixedData.append(contentsOf: [
UInt8(truncatingIfNeeded: length >> 24),
UInt8(truncatingIfNeeded: length >> 16),
UInt8(truncatingIfNeeded: length >> 8),
UInt8(truncatingIfNeeded: length)
])
lengthPrefixedData.append(frame)
connection.send(content: lengthPrefixedData, completion: .contentProcessed({ error in
if let completion=completion{
completion()
}
}))
}
internal func encryptAndSendOfflineFrame(_ frame:Location_Nearby_Connections_OfflineFrame, completion:(()->Void)?=nil) throws{
var d2dMsg=Securegcm_DeviceToDeviceMessage()
serverSeq+=1
d2dMsg.sequenceNumber=serverSeq
d2dMsg.message=try frame.serializedData()
let serializedMsg=[UInt8](try d2dMsg.serializedData())
let iv=Data.randomData(length: 16)
var encryptedData=Data(count: serializedMsg.count+16)
var encryptedLength:size_t=0
encryptedData.withUnsafeMutableBytes({
let status=CCCrypt(
CCOperation(kCCEncrypt),
CCAlgorithm(kCCAlgorithmAES128),
CCOptions(kCCOptionPKCS7Padding),
encryptKey, kCCKeySizeAES256,
[UInt8](iv),
serializedMsg, serializedMsg.count,
$0.baseAddress, $0.count,
&encryptedLength
)
guard status==kCCSuccess else { fatalError("CCCrypt error: \(status)") }
})
var hb=Securemessage_HeaderAndBody()
hb.body=encryptedData.prefix(encryptedLength)
hb.header=Securemessage_Header()
hb.header.encryptionScheme = .aes256Cbc
hb.header.signatureScheme = .hmacSha256
hb.header.iv=iv
var md=Securegcm_GcmMetadata()
md.type = .deviceToDeviceMessage
md.version=1
hb.header.publicMetadata=try md.serializedData()
var smsg=Securemessage_SecureMessage()
smsg.headerAndBody=try hb.serializedData()
smsg.signature=Data(HMAC<SHA256>.authenticationCode(for: smsg.headerAndBody, using: sendHmacKey!))
sendFrameAsync(try smsg.serializedData(), completion: completion)
}
internal func sendTransferSetupFrame(_ frame:Sharing_Nearby_Frame) throws{
var transfer=Location_Nearby_Connections_PayloadTransferFrame()
transfer.packetType = .data
transfer.payloadChunk.offset=0
transfer.payloadChunk.flags=0
transfer.payloadChunk.body=try frame.serializedData()
transfer.payloadHeader.id=Int64.random(in: Int64.min...Int64.max)
transfer.payloadHeader.type = .bytes
transfer.payloadHeader.totalSize=Int64(transfer.payloadChunk.body.count)
transfer.payloadHeader.isSensitive=false
var wrapper=Location_Nearby_Connections_OfflineFrame()
wrapper.version = .v1
wrapper.v1=Location_Nearby_Connections_V1Frame()
wrapper.v1.type = .payloadTransfer
wrapper.v1.payloadTransfer=transfer
try encryptAndSendOfflineFrame(wrapper)
transfer.payloadChunk.flags=1 // .lastChunk
transfer.payloadChunk.offset=Int64(transfer.payloadChunk.body.count)
transfer.payloadChunk.clearBody()
wrapper.v1.payloadTransfer=transfer
try encryptAndSendOfflineFrame(wrapper)
}
internal func decryptAndProcessReceivedSecureMessage(_ smsg:Securemessage_SecureMessage) throws{
guard smsg.hasSignature, smsg.hasHeaderAndBody else { throw NearbyError.requiredFieldMissing }
let hmac=Data(HMAC<SHA256>.authenticationCode(for: smsg.headerAndBody, using: recvHmacKey!))
guard hmac==smsg.signature else { throw NearbyError.protocolError("hmac!=signature") }
let headerAndBody=try Securemessage_HeaderAndBody(serializedData: smsg.headerAndBody)
var decryptedData=Data(count: headerAndBody.body.count)
var decryptedLength:Int=0
decryptedData.withUnsafeMutableBytes({
let status=CCCrypt(
CCOperation(kCCDecrypt),
CCAlgorithm(kCCAlgorithmAES128),
CCOptions(kCCOptionPKCS7Padding),
decryptKey, kCCKeySizeAES256,
[UInt8](headerAndBody.header.iv),
[UInt8](headerAndBody.body), headerAndBody.body.count,
$0.baseAddress, $0.count,
&decryptedLength
)
guard status==kCCSuccess else { fatalError("CCCrypt error: \(status)") }
})
decryptedData=decryptedData.prefix(decryptedLength)
let d2dMsg=try Securegcm_DeviceToDeviceMessage(serializedData: decryptedData)
guard d2dMsg.hasMessage, d2dMsg.hasSequenceNumber else { throw NearbyError.requiredFieldMissing }
clientSeq+=1
guard d2dMsg.sequenceNumber==clientSeq else { throw NearbyError.protocolError("Wrong sequence number. Expected \(clientSeq), got \(d2dMsg.sequenceNumber)") }
let offlineFrame=try Location_Nearby_Connections_OfflineFrame(serializedData: d2dMsg.message)
guard offlineFrame.hasV1, offlineFrame.v1.hasType else { throw NearbyError.requiredFieldMissing }
if case .payloadTransfer = offlineFrame.v1.type {
guard offlineFrame.v1.hasPayloadTransfer else { throw NearbyError.requiredFieldMissing }
let payloadTransfer=offlineFrame.v1.payloadTransfer
let header=payloadTransfer.payloadHeader;
let chunk=payloadTransfer.payloadChunk;
guard header.hasType, header.hasID else { throw NearbyError.requiredFieldMissing }
guard payloadTransfer.hasPayloadChunk, chunk.hasOffset, chunk.hasFlags else { throw NearbyError.requiredFieldMissing }
if case .bytes = header.type{
let payloadID=header.id
if header.totalSize>InboundNearbyConnection.SANE_FRAME_LENGTH{
payloadBuffers.removeValue(forKey: payloadID)
throw NearbyError.protocolError("Payload too large (\(header.totalSize) bytes)")
}
if payloadBuffers[payloadID]==nil {
payloadBuffers[payloadID]=NSMutableData(capacity: Int(header.totalSize))
}
let buffer=payloadBuffers[payloadID]!
guard chunk.offset==buffer.count else {
payloadBuffers.removeValue(forKey: payloadID)
throw NearbyError.protocolError("Unexpected chunk offset \(chunk.offset), expected \(buffer.count)")
}
if chunk.hasBody {
buffer.append(chunk.body)
}
if (chunk.flags & 1)==1 {
payloadBuffers.removeValue(forKey: payloadID)
let innerFrame=try Sharing_Nearby_Frame(serializedData: buffer as Data)
try processTransferSetupFrame(innerFrame)
}
}else if case .file = header.type{
try processFileChunk(frame: payloadTransfer)
}
}else if case .keepAlive = offlineFrame.v1.type{
#if DEBUG
print("Sent keep-alive")
#endif
sendKeepAlive(ack: true)
}else{
print("Unhandled offline frame encrypted: \(offlineFrame)")
}
}
internal static func pinCodeFromAuthKey(_ key:SymmetricKey) -> String{
var hash:Int=0
var multiplier:Int=1
let keyBytes:[UInt8]=key.withUnsafeBytes({
return [UInt8]($0)
})
for _byte in keyBytes {
let byte=Int(Int8(bitPattern: _byte))
hash=(hash+byte*multiplier)%9973
multiplier=(multiplier*31)%9973
}
return String(format: "%04d", abs(hash))
}
internal func finalizeKeyExchange(peerKey:Securemessage_GenericPublicKey) throws{
guard peerKey.hasEcP256PublicKey else { throw NearbyError.requiredFieldMissing }
let domain=Domain.instance(curve: .EC256r1)
var clientX=peerKey.ecP256PublicKey.x
var clientY=peerKey.ecP256PublicKey.y
if clientX.count>32{
clientX=clientX.suffix(32)
}
if clientY.count>32{
clientY=clientY.suffix(32)
}
let key=try ECPublicKey(domain: domain, w: Point(BInt(magnitude: [UInt8](clientX)), BInt(magnitude: [UInt8](clientY))))
let dhs=(try privateKey?.domain.multiplyPoint(key.w, privateKey!.s).x.asMagnitudeBytes())!
var sha=SHA256()
sha.update(data: dhs)
let derivedSecretKey=Data(sha.finalize())
var ukeyInfo=Data()
ukeyInfo.append(ukeyClientInitMsgData!)
ukeyInfo.append(ukeyServerInitMsgData!)
let authString=HKDF<SHA256>.deriveKey(inputKeyMaterial: SymmetricKey(data: derivedSecretKey), salt: "UKEY2 v1 auth".data(using: .utf8)!, info: ukeyInfo, outputByteCount: 32)
let nextSecret=HKDF<SHA256>.deriveKey(inputKeyMaterial: SymmetricKey(data: derivedSecretKey), salt: "UKEY2 v1 next".data(using: .utf8)!, info: ukeyInfo, outputByteCount: 32)
pinCode=NearbyConnection.pinCodeFromAuthKey(authString)
let salt:Data=Data([0x82, 0xAA, 0x55, 0xA0, 0xD3, 0x97, 0xF8, 0x83, 0x46, 0xCA, 0x1C,
0xEE, 0x8D, 0x39, 0x09, 0xB9, 0x5F, 0x13, 0xFA, 0x7D, 0xEB, 0x1D,
0x4A, 0xB3, 0x83, 0x76, 0xB8, 0x25, 0x6D, 0xA8, 0x55, 0x10])
let d2dClientKey=HKDF<SHA256>.deriveKey(inputKeyMaterial: nextSecret, salt: salt, info: "client".data(using: .utf8)!, outputByteCount: 32)
let d2dServerKey=HKDF<SHA256>.deriveKey(inputKeyMaterial: nextSecret, salt: salt, info: "server".data(using: .utf8)!, outputByteCount: 32)
sha=SHA256()
sha.update(data: "SecureMessage".data(using: .utf8)!)
let smsgSalt=Data(sha.finalize())
let clientKey=HKDF<SHA256>.deriveKey(inputKeyMaterial: d2dClientKey, salt: smsgSalt, info: "ENC:2".data(using: .utf8)!, outputByteCount: 32).withUnsafeBytes({return [UInt8]($0)})
let clientHmacKey=HKDF<SHA256>.deriveKey(inputKeyMaterial: d2dClientKey, salt: smsgSalt, info: "SIG:1".data(using: .utf8)!, outputByteCount: 32)
let serverKey=HKDF<SHA256>.deriveKey(inputKeyMaterial: d2dServerKey, salt: smsgSalt, info: "ENC:2".data(using: .utf8)!, outputByteCount: 32).withUnsafeBytes({return [UInt8]($0)})
let serverHmacKey=HKDF<SHA256>.deriveKey(inputKeyMaterial: d2dServerKey, salt: smsgSalt, info: "SIG:1".data(using: .utf8)!, outputByteCount: 32)
if isServer(){
decryptKey=clientKey
recvHmacKey=clientHmacKey
encryptKey=serverKey
sendHmacKey=serverHmacKey
}else{
decryptKey=serverKey
recvHmacKey=serverHmacKey
encryptKey=clientKey
sendHmacKey=clientHmacKey
}
}
internal func disconnect(){
connection.send(content: nil, isComplete: true, completion: .contentProcessed({ error in
self.handleConnectionClosure()
}))
connectionClosed=true
}
internal func sendDisconnectionAndDisconnect() throws{
var offlineFrame=Location_Nearby_Connections_OfflineFrame()
offlineFrame.version = .v1
offlineFrame.v1.type = .disconnection
offlineFrame.v1.disconnection=Location_Nearby_Connections_DisconnectionFrame()
if encryptionDone{
try encryptAndSendOfflineFrame(offlineFrame)
}else{
sendFrameAsync(try offlineFrame.serializedData())
}
disconnect()
}
internal func sendUkey2Alert(type:Securegcm_Ukey2Alert.AlertType){
var alert=Securegcm_Ukey2Alert()
alert.type=type
var msg=Securegcm_Ukey2Message()
msg.messageType = .alert
msg.messageData = try! alert.serializedData()
sendFrameAsync(try! msg.serializedData())
disconnect()
}
internal func sendKeepAlive(ack:Bool){
var offlineFrame=Location_Nearby_Connections_OfflineFrame()
offlineFrame.version = .v1
offlineFrame.v1.type = .keepAlive
offlineFrame.v1.keepAlive.ack=ack
do{
if encryptionDone{
try encryptAndSendOfflineFrame(offlineFrame)
}else{
sendFrameAsync(try offlineFrame.serializedData())
}
}catch{
print("Error sending KEEP_ALIVE: \(error)")
}
}
}
struct InternalFileInfo{
let meta:FileMetadata
let payloadID:Int64
let destinationURL:URL
var bytesTransferred:Int64=0
var fileHandle:FileHandle?
var progress:Progress?
var created:Bool=false
}

View File

@@ -0,0 +1,374 @@
//
// NearbyConnectionManager.swift
// NearDrop
//
// Created by Grishka on 08.04.2023.
//
import Foundation
import Network
import System
public struct RemoteDeviceInfo{
public let name:String
public let type:DeviceType
public var id:String?
init(name: String, type: DeviceType, id: String? = nil) {
self.name = name
self.type = type
self.id = id
}
init(info:EndpointInfo){
self.name=info.name
self.type=info.deviceType
}
public enum DeviceType:Int32{
case unknown=0
case phone
case tablet
case computer
public static func fromRawValue(value:Int) -> DeviceType{
switch value {
case 0:
return .unknown
case 1:
return .phone
case 2:
return .tablet
case 3:
return .computer
default:
return .unknown
}
}
}
}
public enum NearbyError:Error{
case protocolError(_ message:String)
case requiredFieldMissing
case ukey2
case inputOutput(cause:Errno)
case canceled(reason:CancellationReason)
public enum CancellationReason{
case userRejected, userCanceled, notEnoughSpace, unsupportedType, timedOut
}
}
public struct TransferMetadata{
public let files:[FileMetadata]
public let id:String
public let pinCode:String?
}
public struct FileMetadata{
public let name:String
public let size:Int64
public let mimeType:String
}
struct FoundServiceInfo{
let service:NWBrowser.Result
var device:RemoteDeviceInfo?
}
struct OutgoingTransferInfo{
let service:NWBrowser.Result
let device:RemoteDeviceInfo
let connection:OutboundNearbyConnection
let delegate:ShareExtensionDelegate
}
struct EndpointInfo{
let name:String
let deviceType:RemoteDeviceInfo.DeviceType
init(name: String, deviceType: RemoteDeviceInfo.DeviceType){
self.name = name
self.deviceType = deviceType
}
init?(data:Data){
guard data.count>17 else {return nil}
let deviceNameLength=Int(data[17])
guard data.count>=deviceNameLength+18 else {return nil}
guard let deviceName=String(data: data[18..<(18+deviceNameLength)], encoding: .utf8) else {return nil}
let rawDeviceType:Int=Int(data[0] & 7) >> 1
self.name=deviceName
self.deviceType=RemoteDeviceInfo.DeviceType.fromRawValue(value: rawDeviceType)
}
func serialize()->Data{
// 1 byte: Version(3 bits)|Visibility(1 bit)|Device Type(3 bits)|Reserved(1 bits)
// Device types: unknown=0, phone=1, tablet=2, laptop=3
var endpointInfo:[UInt8]=[UInt8(deviceType.rawValue << 1)]
// 16 bytes: unknown random bytes
for _ in 0...15{
endpointInfo.append(UInt8.random(in: 0...255))
}
// Device name in UTF-8 prefixed with 1-byte length
var nameChars=[UInt8](name.utf8)
if nameChars.count>255{
nameChars=[UInt8](nameChars[0..<255])
}
endpointInfo.append(UInt8(nameChars.count))
for ch in nameChars{
endpointInfo.append(UInt8(ch))
}
return Data(endpointInfo)
}
}
public protocol MainAppDelegate{
func obtainUserConsent(for transfer:TransferMetadata, from device:RemoteDeviceInfo)
func incomingTransfer(id:String, didFinishWith error:Error?)
}
public protocol ShareExtensionDelegate:AnyObject{
func addDevice(device:RemoteDeviceInfo)
func removeDevice(id:String)
func connectionWasEstablished(pinCode:String)
func connectionFailed(with error:Error)
func transferAccepted()
func transferProgress(progress:Double)
func transferFinished()
}
public class NearbyConnectionManager : NSObject, NetServiceDelegate, InboundNearbyConnectionDelegate, OutboundNearbyConnectionDelegate{
private var tcpListener:NWListener;
public let endpointID:[UInt8]=generateEndpointID()
private var mdnsService:NetService?
private var activeConnections:[String:InboundNearbyConnection]=[:]
private var foundServices:[String:FoundServiceInfo]=[:]
private var shareExtensionDelegates:[ShareExtensionDelegate]=[]
private var outgoingTransfers:[String:OutgoingTransferInfo]=[:]
public var mainAppDelegate:(any MainAppDelegate)?
private var discoveryRefCount=0
private var browser:NWBrowser?
public static let shared=NearbyConnectionManager()
override init() {
tcpListener=try! NWListener(using: NWParameters(tls: .none))
super.init()
}
public func becomeVisible(){
startTCPListener()
}
private func startTCPListener(){
tcpListener.stateUpdateHandler={(state:NWListener.State) in
if case .ready = state {
self.initMDNS()
}
}
tcpListener.newConnectionHandler={(connection:NWConnection) in
let id=UUID().uuidString
let conn=InboundNearbyConnection(connection: connection, id: id)
self.activeConnections[id]=conn
conn.delegate=self
conn.start()
}
tcpListener.start(queue: .global(qos: .utility))
}
private static func generateEndpointID()->[UInt8]{
var id:[UInt8]=[]
let alphabet="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".compactMap {UInt8($0.asciiValue!)}
for _ in 0...3{
id.append(alphabet[Int.random(in: 0..<alphabet.count)])
}
return id
}
private func initMDNS(){
let nameBytes:[UInt8]=[
0x23, // PCP
endpointID[0], endpointID[1], endpointID[2], endpointID[3],
0xFC, 0x9F, 0x5E, // Service ID hash
0, 0
]
let name=Data(nameBytes).urlSafeBase64EncodedString()
let endpointInfo=EndpointInfo(name: Host.current().localizedName!, deviceType: .computer)
let port:Int32=Int32(tcpListener.port!.rawValue)
mdnsService=NetService(domain: "", type: "_FC9F5ED42C8A._tcp.", name: name, port: port)
mdnsService?.delegate=self
mdnsService?.includesPeerToPeer=true
mdnsService?.setTXTRecord(NetService.data(fromTXTRecord: [
"n": endpointInfo.serialize().urlSafeBase64EncodedString().data(using: .utf8)!
]))
mdnsService?.publish()
}
func obtainUserConsent(for transfer: TransferMetadata, from device: RemoteDeviceInfo, connection: InboundNearbyConnection) {
guard let delegate=mainAppDelegate else {return}
delegate.obtainUserConsent(for: transfer, from: device)
}
func connectionWasTerminated(connection:InboundNearbyConnection, error:Error?){
guard let delegate=mainAppDelegate else {return}
delegate.incomingTransfer(id: connection.id, didFinishWith: error)
activeConnections.removeValue(forKey: connection.id)
}
public func submitUserConsent(transferID:String, accept:Bool){
guard let conn=activeConnections[transferID] else {return}
conn.submitUserConsent(accepted: accept)
}
public func startDeviceDiscovery(){
if discoveryRefCount==0{
foundServices.removeAll()
if browser==nil{
browser=NWBrowser(for: .bonjourWithTXTRecord(type: "_FC9F5ED42C8A._tcp.", domain: nil), using: .tcp)
browser?.browseResultsChangedHandler={newResults, changes in
for change in changes{
switch change{
case let .added(res):
self.maybeAddFoundDevice(service: res)
case let .removed(res):
self.maybeRemoveFoundDevice(service: res)
default:
break
}
}
}
}
browser?.start(queue: .main)
}
discoveryRefCount+=1
}
public func stopDeviceDiscovery(){
discoveryRefCount-=1
assert(discoveryRefCount>=0)
if discoveryRefCount==0{
browser?.cancel()
browser=nil
}
}
public func addShareExtensionDelegate(_ delegate:ShareExtensionDelegate){
shareExtensionDelegates.append(delegate)
for service in foundServices.values{
guard let device=service.device else {continue}
delegate.addDevice(device: device)
}
}
public func removeShareExtensionDelegate(_ delegate:ShareExtensionDelegate){
shareExtensionDelegates.removeAll(where: {$0===delegate})
}
public func cancelOutgoingTransfer(id:String){
guard let transfer=outgoingTransfers[id] else {return}
transfer.connection.cancel()
}
private func endpointID(for service:NWBrowser.Result)->String?{
guard case let NWEndpoint.service(name: serviceName, type: _, domain: _, interface: _)=service.endpoint else {return nil}
guard let nameData=Data.dataFromUrlSafeBase64(serviceName) else {return nil}
guard nameData.count>=10 else {return nil}
let pcp=nameData[0]
guard pcp==0x23 else {return nil}
let endpointID=String(data: nameData.subdata(in: 1..<5), encoding: .ascii)!
let serviceIDHash=nameData.subdata(in: 5..<8)
guard serviceIDHash==Data([0xFC, 0x9F, 0x5E]) else {return nil}
return endpointID
}
private func maybeAddFoundDevice(service:NWBrowser.Result){
#if DEBUG
print("found service \(service)")
#endif
guard let endpointID=endpointID(for: service) else {return}
#if DEBUG
print("service name is valid, endpoint ID \(endpointID)")
#endif
var foundService=FoundServiceInfo(service: service)
guard case let NWBrowser.Result.Metadata.bonjour(txtRecord)=service.metadata else {return}
guard let endpointInfoEncoded=txtRecord.dictionary["n"] else {return}
guard let endpointInfo=Data.dataFromUrlSafeBase64(endpointInfoEncoded) else {return}
guard endpointInfo.count>=19 else {return}
let deviceType=RemoteDeviceInfo.DeviceType.fromRawValue(value: (Int(endpointInfo[0]) >> 1) & 7)
let deviceNameLength=Int(endpointInfo[17])
guard endpointInfo.count>=deviceNameLength+17 else {return}
guard let deviceName=String(data: endpointInfo.subdata(in: 18..<(18+deviceNameLength)), encoding: .utf8) else {return}
let deviceInfo=RemoteDeviceInfo(name: deviceName, type: deviceType, id: endpointID)
foundService.device=deviceInfo
foundServices[endpointID]=foundService
for delegate in shareExtensionDelegates{
delegate.addDevice(device: deviceInfo)
}
}
private func maybeRemoveFoundDevice(service:NWBrowser.Result){
guard let endpointID=endpointID(for: service) else {return}
guard let _=foundServices.removeValue(forKey: endpointID) else {return}
for delegate in shareExtensionDelegates {
delegate.removeDevice(id: endpointID)
}
}
public func startOutgoingTransfer(deviceID:String, delegate:ShareExtensionDelegate, urls:[URL]){
guard let info=foundServices[deviceID] else {return}
let tcp=NWProtocolTCP.Options.init()
tcp.noDelay=true
let nwconn=NWConnection(to: info.service.endpoint, using: NWParameters(tls: .none, tcp: tcp))
let conn=OutboundNearbyConnection(connection: nwconn, id: deviceID, urlsToSend: urls)
conn.delegate=self
let transfer=OutgoingTransferInfo(service: info.service, device: info.device!, connection: conn, delegate: delegate)
outgoingTransfers[deviceID]=transfer
conn.start()
}
func outboundConnectionWasEstablished(connection: OutboundNearbyConnection) {
guard let transfer=outgoingTransfers[connection.id] else {return}
DispatchQueue.main.async {
transfer.delegate.connectionWasEstablished(pinCode: connection.pinCode!)
}
}
func outboundConnectionTransferAccepted(connection: OutboundNearbyConnection) {
guard let transfer=outgoingTransfers[connection.id] else {return}
DispatchQueue.main.async {
transfer.delegate.transferAccepted()
}
}
func outboundConnection(connection: OutboundNearbyConnection, transferProgress: Double) {
guard let transfer=outgoingTransfers[connection.id] else {return}
DispatchQueue.main.async {
transfer.delegate.transferProgress(progress: transferProgress)
}
}
func outboundConnection(connection: OutboundNearbyConnection, failedWithError: Error) {
guard let transfer=outgoingTransfers[connection.id] else {return}
DispatchQueue.main.async {
transfer.delegate.connectionFailed(with: failedWithError)
}
outgoingTransfers.removeValue(forKey: connection.id)
}
func outboundConnectionTransferFinished(connection: OutboundNearbyConnection) {
guard let transfer=outgoingTransfers[connection.id] else {return}
DispatchQueue.main.async {
transfer.delegate.transferFinished()
}
outgoingTransfers.removeValue(forKey: connection.id)
}
}

View File

@@ -0,0 +1,424 @@
//
// OutboundNearbyConnection.swift
// NearbyShare
//
// Created by Grishka on 23.09.2023.
//
import Foundation
import Network
import CryptoKit
import CommonCrypto
import System
import UniformTypeIdentifiers
import SwiftECC
import BigInt
class OutboundNearbyConnection:NearbyConnection{
private var currentState:State = .initial
private let urlsToSend:[URL]
private var ukeyClientFinishMsgData:Data?
private var queue:[OutgoingFileTransfer]=[]
private var currentTransfer:OutgoingFileTransfer?
public var delegate:OutboundNearbyConnectionDelegate?
private var totalBytesToSend:Int64=0
private var totalBytesSent:Int64=0
private var cancelled:Bool=false
enum State{
case initial, sentUkeyClientInit, sentUkeyClientFinish, sentPairedKeyEncryption, sentPairedKeyResult, sentIntroduction, sendingFiles
}
init(connection: NWConnection, id: String, urlsToSend:[URL]){
self.urlsToSend=urlsToSend
super.init(connection: connection, id: id)
}
deinit {
if let transfer=currentTransfer, let handle=transfer.handle{
try? handle.close()
}
for transfer in queue{
if let handle=transfer.handle{
try? handle.close()
}
}
}
public func cancel(){
cancelled=true
if encryptionDone{
var cancel=Sharing_Nearby_Frame()
cancel.version = .v1
cancel.v1=Sharing_Nearby_V1Frame()
cancel.v1.type = .cancel
try? sendTransferSetupFrame(cancel)
}
try? sendDisconnectionAndDisconnect()
}
override func connectionReady() {
super.connectionReady()
do{
try sendConnectionRequest()
try sendUkey2ClientInit()
}catch{
lastError=error
protocolError()
}
}
override func isServer() -> Bool {
return false
}
override func processReceivedFrame(frameData: Data) {
do{
#if DEBUG
print("received \(frameData), state is \(currentState)")
#endif
switch currentState {
case .initial:
protocolError()
case .sentUkeyClientInit:
try processUkey2ServerInit(frame: try Securegcm_Ukey2Message(serializedData: frameData), raw: frameData)
case .sentUkeyClientFinish:
try processConnectionResponse(frame: try Location_Nearby_Connections_OfflineFrame(serializedData: frameData))
default:
let smsg=try Securemessage_SecureMessage(serializedData: frameData)
try decryptAndProcessReceivedSecureMessage(smsg)
}
}catch{
if case NearbyError.ukey2=error{
}else if currentState == .sentUkeyClientInit{
sendUkey2Alert(type: .badMessage)
}
lastError=error
protocolError()
}
}
override func processTransferSetupFrame(_ frame: Sharing_Nearby_Frame) throws {
if frame.hasV1 && frame.v1.hasType, case .cancel = frame.v1.type {
print("Transfer canceled")
try sendDisconnectionAndDisconnect()
delegate?.outboundConnection(connection: self, failedWithError: NearbyError.canceled(reason: .userCanceled))
return
}
print(frame)
switch currentState{
case .sentPairedKeyEncryption:
try processPairedKeyEncryption(frame: frame)
case .sentPairedKeyResult:
try processPairedKeyResult(frame: frame)
case .sentIntroduction:
try processConsent(frame: frame)
case .sendingFiles:
break
default:
assertionFailure("Unexpected state \(currentState)")
}
}
override func protocolError() {
super.protocolError()
delegate?.outboundConnection(connection: self, failedWithError: lastError!)
}
private func sendConnectionRequest() throws {
var frame=Location_Nearby_Connections_OfflineFrame()
frame.version = .v1
frame.v1=Location_Nearby_Connections_V1Frame()
frame.v1.type = .connectionRequest
frame.v1.connectionRequest=Location_Nearby_Connections_ConnectionRequestFrame()
frame.v1.connectionRequest.endpointID=String(bytes: NearbyConnectionManager.shared.endpointID, encoding: .ascii)!
frame.v1.connectionRequest.endpointName=Host.current().localizedName!
let endpointInfo=EndpointInfo(name: Host.current().localizedName!, deviceType: .computer)
frame.v1.connectionRequest.endpointInfo=endpointInfo.serialize()
frame.v1.connectionRequest.mediums=[.wifiLan]
sendFrameAsync(try frame.serializedData())
}
private func sendUkey2ClientInit() throws {
let domain=Domain.instance(curve: .EC256r1)
let (pubKey, privKey)=domain.makeKeyPair()
publicKey=pubKey
privateKey=privKey
var finishFrame=Securegcm_Ukey2Message()
finishFrame.messageType = .clientFinish
var finish=Securegcm_Ukey2ClientFinished()
var pkey=Securemessage_GenericPublicKey()
pkey.type = .ecP256
pkey.ecP256PublicKey=Securemessage_EcP256PublicKey()
pkey.ecP256PublicKey.x=Data(pubKey.w.x.asSignedBytes())
pkey.ecP256PublicKey.y=Data(pubKey.w.y.asSignedBytes())
finish.publicKey=try pkey.serializedData()
finishFrame.messageData=try finish.serializedData()
ukeyClientFinishMsgData=try finishFrame.serializedData()
var frame=Securegcm_Ukey2Message()
frame.messageType = .clientInit
var clientInit=Securegcm_Ukey2ClientInit()
clientInit.version=1
clientInit.random=Data.randomData(length: 32)
clientInit.nextProtocol="AES_256_CBC-HMAC_SHA256"
var sha=SHA512()
sha.update(data: ukeyClientFinishMsgData!)
var commitment=Securegcm_Ukey2ClientInit.CipherCommitment()
commitment.commitment=Data(sha.finalize())
commitment.handshakeCipher = .p256Sha512
clientInit.cipherCommitments.append(commitment)
frame.messageData=try clientInit.serializedData()
ukeyClientInitMsgData=try frame.serializedData()
sendFrameAsync(ukeyClientInitMsgData!)
currentState = .sentUkeyClientInit
}
private func processUkey2ServerInit(frame:Securegcm_Ukey2Message, raw:Data) throws{
ukeyServerInitMsgData=raw
guard frame.messageType == .serverInit else{
sendUkey2Alert(type: .badMessageType)
throw NearbyError.ukey2
}
let serverInit=try Securegcm_Ukey2ServerInit(serializedData: frame.messageData)
guard serverInit.version==1 else{
sendUkey2Alert(type: .badVersion)
throw NearbyError.ukey2
}
guard serverInit.random.count==32 else{
sendUkey2Alert(type: .badRandom)
throw NearbyError.ukey2
}
guard serverInit.handshakeCipher == .p256Sha512 else{
sendUkey2Alert(type: .badHandshakeCipher)
throw NearbyError.ukey2
}
let serverKey=try Securemessage_GenericPublicKey(serializedData: serverInit.publicKey)
try finalizeKeyExchange(peerKey: serverKey)
sendFrameAsync(ukeyClientFinishMsgData!)
currentState = .sentUkeyClientFinish
var resp=Location_Nearby_Connections_OfflineFrame()
resp.version = .v1
resp.v1=Location_Nearby_Connections_V1Frame()
resp.v1.type = .connectionResponse
resp.v1.connectionResponse=Location_Nearby_Connections_ConnectionResponseFrame()
resp.v1.connectionResponse.response = .accept
resp.v1.connectionResponse.status=0
resp.v1.connectionResponse.osInfo=Location_Nearby_Connections_OsInfo()
resp.v1.connectionResponse.osInfo.type = .apple
sendFrameAsync(try resp.serializedData())
encryptionDone=true
delegate?.outboundConnectionWasEstablished(connection: self)
}
private func processConnectionResponse(frame:Location_Nearby_Connections_OfflineFrame) throws{
#if DEBUG
print("connection response: \(frame)")
#endif
guard frame.version == .v1 else {throw NearbyError.protocolError("Unexpected offline frame version \(frame.version)")}
guard frame.v1.type == .connectionResponse else {throw NearbyError.protocolError("Unexpected frame type \(frame.v1.type)")}
guard frame.v1.connectionResponse.response == .accept else {throw NearbyError.protocolError("Connection was rejected by recipient")}
var pairedEncryption=Sharing_Nearby_Frame()
pairedEncryption.version = .v1
pairedEncryption.v1=Sharing_Nearby_V1Frame()
pairedEncryption.v1.type = .pairedKeyEncryption
pairedEncryption.v1.pairedKeyEncryption=Sharing_Nearby_PairedKeyEncryptionFrame()
pairedEncryption.v1.pairedKeyEncryption.secretIDHash=Data.randomData(length: 6)
pairedEncryption.v1.pairedKeyEncryption.signedData=Data.randomData(length: 72)
try sendTransferSetupFrame(pairedEncryption)
currentState = .sentPairedKeyEncryption
}
private func processPairedKeyEncryption(frame:Sharing_Nearby_Frame) throws{
guard frame.hasV1, frame.v1.hasPairedKeyEncryption else { throw NearbyError.requiredFieldMissing }
var pairedResult=Sharing_Nearby_Frame()
pairedResult.version = .v1
pairedResult.v1=Sharing_Nearby_V1Frame()
pairedResult.v1.type = .pairedKeyResult
pairedResult.v1.pairedKeyResult=Sharing_Nearby_PairedKeyResultFrame()
pairedResult.v1.pairedKeyResult.status = .unable
try sendTransferSetupFrame(pairedResult)
currentState = .sentPairedKeyResult
}
private func processPairedKeyResult(frame:Sharing_Nearby_Frame) throws{
guard frame.hasV1, frame.v1.hasPairedKeyResult else { throw NearbyError.requiredFieldMissing }
var introduction=Sharing_Nearby_Frame()
introduction.version = .v1
introduction.v1.type = .introduction
if urlsToSend.count==1 && urlsToSend[0].scheme != "file"{
var meta=Sharing_Nearby_TextMetadata()
meta.type = .url
meta.textTitle=urlsToSend[0].host ?? "URL"
meta.size=Int64(urlsToSend[0].absoluteString.utf8.count)
meta.payloadID=Int64.random(in: Int64.min...Int64.max)
introduction.v1.introduction.textMetadata.append(meta)
}else{
for url in urlsToSend{
guard url.scheme=="file" else {continue}
var meta=Sharing_Nearby_FileMetadata()
meta.name=OutboundNearbyConnection.sanitizeFileName(name: url.lastPathComponent)
let attrs=try FileManager.default.attributesOfItem(atPath: url.path)
meta.size=(attrs[FileAttributeKey.size] as! NSNumber).int64Value
let typeID=try? url.resourceValues(forKeys: [.typeIdentifierKey]).typeIdentifier
meta.mimeType="application/octet-stream"
if let typeID=typeID{
let type=UTType(typeID)
if let type=type, let mimeType=type.preferredMIMEType{
meta.mimeType=mimeType
}
}
if meta.mimeType.starts(with: "image/"){
meta.type = .image
}else if meta.mimeType.starts(with: "video/"){
meta.type = .video
}else if(meta.mimeType.starts(with: "audio/")){
meta.type = .audio
}else if(url.pathExtension.lowercased()=="apk"){
meta.type = .app
}else{
meta.type = .unknown
}
meta.payloadID=Int64.random(in: Int64.min...Int64.max)
queue.append(OutgoingFileTransfer(url: url, payloadID: meta.payloadID, handle: try FileHandle(forReadingFrom: url), totalBytes: meta.size, currentOffset: 0))
introduction.v1.introduction.fileMetadata.append(meta)
totalBytesToSend+=meta.size
}
}
#if DEBUG
print("sent introduction: \(introduction)")
#endif
try sendTransferSetupFrame(introduction)
currentState = .sentIntroduction
}
private func processConsent(frame:Sharing_Nearby_Frame) throws{
guard frame.version == .v1, frame.v1.type == .response else {throw NearbyError.requiredFieldMissing}
switch frame.v1.connectionResponse.status{
case .accept:
currentState = .sendingFiles
delegate?.outboundConnectionTransferAccepted(connection: self)
try sendNextFileChunk()
case .reject, .unknown:
delegate?.outboundConnection(connection: self, failedWithError: NearbyError.canceled(reason: .userRejected))
try sendDisconnectionAndDisconnect()
case .notEnoughSpace:
delegate?.outboundConnection(connection: self, failedWithError: NearbyError.canceled(reason: .notEnoughSpace))
try sendDisconnectionAndDisconnect()
case .timedOut:
delegate?.outboundConnection(connection: self, failedWithError: NearbyError.canceled(reason: .timedOut))
try sendDisconnectionAndDisconnect()
case .unsupportedAttachmentType:
delegate?.outboundConnection(connection: self, failedWithError: NearbyError.canceled(reason: .unsupportedType))
try sendDisconnectionAndDisconnect()
}
}
private func sendNextFileChunk() throws{
print("SEND NEXT: \(Thread.current)")
if cancelled{
return
}
if currentTransfer==nil || currentTransfer?.currentOffset==currentTransfer?.totalBytes{
if currentTransfer != nil && currentTransfer?.handle != nil{
try currentTransfer?.handle?.close()
}
if queue.isEmpty{
#if DEBUG
print("Disconnecting because all files have been transferred")
#endif
try sendDisconnectionAndDisconnect()
delegate?.outboundConnectionTransferFinished(connection: self)
return
}
currentTransfer=queue.removeFirst()
}
guard let fileBuffer=try currentTransfer!.handle!.read(upToCount: 512*1024) else{
throw NearbyError.inputOutput(cause: Errno.ioError)
}
var transfer=Location_Nearby_Connections_PayloadTransferFrame()
transfer.packetType = .data
transfer.payloadChunk.offset=currentTransfer!.currentOffset
transfer.payloadChunk.flags=0
transfer.payloadChunk.body=fileBuffer
transfer.payloadHeader.id=currentTransfer!.payloadID
transfer.payloadHeader.type = .file
transfer.payloadHeader.totalSize=Int64(currentTransfer!.totalBytes)
transfer.payloadHeader.isSensitive=false
currentTransfer!.currentOffset+=Int64(fileBuffer.count)
var wrapper=Location_Nearby_Connections_OfflineFrame()
wrapper.version = .v1
wrapper.v1=Location_Nearby_Connections_V1Frame()
wrapper.v1.type = .payloadTransfer
wrapper.v1.payloadTransfer=transfer
try encryptAndSendOfflineFrame(wrapper, completion: {
do{
try self.sendNextFileChunk()
}catch{
self.lastError=error
self.protocolError()
}
})
#if DEBUG
print("sent file chunk, current transfer: \(String(describing: currentTransfer))")
#endif
totalBytesSent+=Int64(fileBuffer.count)
delegate?.outboundConnection(connection: self, transferProgress: Double(totalBytesSent)/Double(totalBytesToSend))
if currentTransfer!.currentOffset==currentTransfer!.totalBytes{
// Signal end of file (yes, all this for one bit)
var transfer=Location_Nearby_Connections_PayloadTransferFrame()
transfer.packetType = .data
transfer.payloadChunk.offset=currentTransfer!.currentOffset
transfer.payloadChunk.flags=1 // <- this one here
transfer.payloadHeader.id=currentTransfer!.payloadID
transfer.payloadHeader.type = .file
transfer.payloadHeader.totalSize=Int64(currentTransfer!.totalBytes)
transfer.payloadHeader.isSensitive=false
var wrapper=Location_Nearby_Connections_OfflineFrame()
wrapper.version = .v1
wrapper.v1=Location_Nearby_Connections_V1Frame()
wrapper.v1.type = .payloadTransfer
wrapper.v1.payloadTransfer=transfer
try encryptAndSendOfflineFrame(wrapper)
#if DEBUG
print("sent EOF, current transfer: \(String(describing: currentTransfer))")
#endif
}
}
private static func sanitizeFileName(name:String)->String{
return name.replacingOccurrences(of: "[\\/\\\\?%\\*:\\|\"<>=]", with: "_", options: .regularExpression)
}
}
fileprivate struct OutgoingFileTransfer{
let url:URL
let payloadID:Int64
let handle:FileHandle?
let totalBytes:Int64
var currentOffset:Int64
}
protocol OutboundNearbyConnectionDelegate{
func outboundConnectionWasEstablished(connection:OutboundNearbyConnection)
func outboundConnection(connection:OutboundNearbyConnection, transferProgress:Double)
func outboundConnectionTransferAccepted(connection:OutboundNearbyConnection)
func outboundConnection(connection:OutboundNearbyConnection, failedWithError:Error)
func outboundConnectionTransferFinished(connection:OutboundNearbyConnection)
}

View File

@@ -0,0 +1,540 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: device_to_device_messages.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
// Copyright 2020 Google LLC
//
// 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
//
// https://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
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
/// Type of curve
enum Securegcm_Curve: SwiftProtobuf.Enum {
typealias RawValue = Int
case ed25519 // = 1
init() {
self = .ed25519
}
init?(rawValue: Int) {
switch rawValue {
case 1: self = .ed25519
default: return nil
}
}
var rawValue: Int {
switch self {
case .ed25519: return 1
}
}
}
#if swift(>=4.2)
extension Securegcm_Curve: CaseIterable {
// Support synthesized by the compiler.
}
#endif // swift(>=4.2)
/// Used by protocols between devices
struct Securegcm_DeviceToDeviceMessage {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// the payload of the message
var message: Data {
get {return _message ?? Data()}
set {_message = newValue}
}
/// Returns true if `message` has been explicitly set.
var hasMessage: Bool {return self._message != nil}
/// Clears the value of `message`. Subsequent reads from it will return its default value.
mutating func clearMessage() {self._message = nil}
/// the sequence number of the message - must be increasing.
var sequenceNumber: Int32 {
get {return _sequenceNumber ?? 0}
set {_sequenceNumber = newValue}
}
/// Returns true if `sequenceNumber` has been explicitly set.
var hasSequenceNumber: Bool {return self._sequenceNumber != nil}
/// Clears the value of `sequenceNumber`. Subsequent reads from it will return its default value.
mutating func clearSequenceNumber() {self._sequenceNumber = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _message: Data? = nil
fileprivate var _sequenceNumber: Int32? = nil
}
/// sent as the first message from initiator to responder
/// in an unauthenticated Diffie-Hellman Key Exchange
struct Securegcm_InitiatorHello {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The session public key to send to the responder
var publicDhKey: Securemessage_GenericPublicKey {
get {return _publicDhKey ?? Securemessage_GenericPublicKey()}
set {_publicDhKey = newValue}
}
/// Returns true if `publicDhKey` has been explicitly set.
var hasPublicDhKey: Bool {return self._publicDhKey != nil}
/// Clears the value of `publicDhKey`. Subsequent reads from it will return its default value.
mutating func clearPublicDhKey() {self._publicDhKey = nil}
/// The protocol version
var protocolVersion: Int32 {
get {return _protocolVersion ?? 0}
set {_protocolVersion = newValue}
}
/// Returns true if `protocolVersion` has been explicitly set.
var hasProtocolVersion: Bool {return self._protocolVersion != nil}
/// Clears the value of `protocolVersion`. Subsequent reads from it will return its default value.
mutating func clearProtocolVersion() {self._protocolVersion = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _publicDhKey: Securemessage_GenericPublicKey? = nil
fileprivate var _protocolVersion: Int32? = nil
}
/// sent inside the header of the first message from the responder to the
/// initiator in an unauthenticated Diffie-Hellman Key Exchange
struct Securegcm_ResponderHello {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// The session public key to send to the initiator
var publicDhKey: Securemessage_GenericPublicKey {
get {return _publicDhKey ?? Securemessage_GenericPublicKey()}
set {_publicDhKey = newValue}
}
/// Returns true if `publicDhKey` has been explicitly set.
var hasPublicDhKey: Bool {return self._publicDhKey != nil}
/// Clears the value of `publicDhKey`. Subsequent reads from it will return its default value.
mutating func clearPublicDhKey() {self._publicDhKey = nil}
/// The protocol version
var protocolVersion: Int32 {
get {return _protocolVersion ?? 0}
set {_protocolVersion = newValue}
}
/// Returns true if `protocolVersion` has been explicitly set.
var hasProtocolVersion: Bool {return self._protocolVersion != nil}
/// Clears the value of `protocolVersion`. Subsequent reads from it will return its default value.
mutating func clearProtocolVersion() {self._protocolVersion = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _publicDhKey: Securemessage_GenericPublicKey? = nil
fileprivate var _protocolVersion: Int32? = nil
}
/// A convenience proto for encoding curve points in affine representation
struct Securegcm_EcPoint {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var curve: Securegcm_Curve {
get {return _curve ?? .ed25519}
set {_curve = newValue}
}
/// Returns true if `curve` has been explicitly set.
var hasCurve: Bool {return self._curve != nil}
/// Clears the value of `curve`. Subsequent reads from it will return its default value.
mutating func clearCurve() {self._curve = nil}
/// x and y are encoded in big-endian two's complement
/// client MUST verify (x,y) is a valid point on the specified curve
var x: Data {
get {return _x ?? Data()}
set {_x = newValue}
}
/// Returns true if `x` has been explicitly set.
var hasX: Bool {return self._x != nil}
/// Clears the value of `x`. Subsequent reads from it will return its default value.
mutating func clearX() {self._x = nil}
var y: Data {
get {return _y ?? Data()}
set {_y = newValue}
}
/// Returns true if `y` has been explicitly set.
var hasY: Bool {return self._y != nil}
/// Clears the value of `y`. Subsequent reads from it will return its default value.
mutating func clearY() {self._y = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _curve: Securegcm_Curve? = nil
fileprivate var _x: Data? = nil
fileprivate var _y: Data? = nil
}
struct Securegcm_SpakeHandshakeMessage {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Each flow in the protocol bumps this counter
var flowNumber: Int32 {
get {return _flowNumber ?? 0}
set {_flowNumber = newValue}
}
/// Returns true if `flowNumber` has been explicitly set.
var hasFlowNumber: Bool {return self._flowNumber != nil}
/// Clears the value of `flowNumber`. Subsequent reads from it will return its default value.
mutating func clearFlowNumber() {self._flowNumber = nil}
/// Some (but not all) SPAKE flows send a point on an elliptic curve
var ecPoint: Securegcm_EcPoint {
get {return _ecPoint ?? Securegcm_EcPoint()}
set {_ecPoint = newValue}
}
/// Returns true if `ecPoint` has been explicitly set.
var hasEcPoint: Bool {return self._ecPoint != nil}
/// Clears the value of `ecPoint`. Subsequent reads from it will return its default value.
mutating func clearEcPoint() {self._ecPoint = nil}
/// Some (but not all) SPAKE flows send a hash value
var hashValue_p: Data {
get {return _hashValue_p ?? Data()}
set {_hashValue_p = newValue}
}
/// Returns true if `hashValue_p` has been explicitly set.
var hasHashValue_p: Bool {return self._hashValue_p != nil}
/// Clears the value of `hashValue_p`. Subsequent reads from it will return its default value.
mutating func clearHashValue_p() {self._hashValue_p = nil}
/// The last flow of a SPAKE protocol can send an optional payload,
/// since the key exchange is already complete on the sender's side.
var payload: Data {
get {return _payload ?? Data()}
set {_payload = newValue}
}
/// Returns true if `payload` has been explicitly set.
var hasPayload: Bool {return self._payload != nil}
/// Clears the value of `payload`. Subsequent reads from it will return its default value.
mutating func clearPayload() {self._payload = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _flowNumber: Int32? = nil
fileprivate var _ecPoint: Securegcm_EcPoint? = nil
fileprivate var _hashValue_p: Data? = nil
fileprivate var _payload: Data? = nil
}
#if swift(>=5.5) && canImport(_Concurrency)
extension Securegcm_Curve: @unchecked Sendable {}
extension Securegcm_DeviceToDeviceMessage: @unchecked Sendable {}
extension Securegcm_InitiatorHello: @unchecked Sendable {}
extension Securegcm_ResponderHello: @unchecked Sendable {}
extension Securegcm_EcPoint: @unchecked Sendable {}
extension Securegcm_SpakeHandshakeMessage: @unchecked Sendable {}
#endif // swift(>=5.5) && canImport(_Concurrency)
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "securegcm"
extension Securegcm_Curve: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "ED_25519"),
]
}
extension Securegcm_DeviceToDeviceMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".DeviceToDeviceMessage"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "message"),
2: .standard(proto: "sequence_number"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularBytesField(value: &self._message) }()
case 2: try { try decoder.decodeSingularInt32Field(value: &self._sequenceNumber) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._message {
try visitor.visitSingularBytesField(value: v, fieldNumber: 1)
} }()
try { if let v = self._sequenceNumber {
try visitor.visitSingularInt32Field(value: v, fieldNumber: 2)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securegcm_DeviceToDeviceMessage, rhs: Securegcm_DeviceToDeviceMessage) -> Bool {
if lhs._message != rhs._message {return false}
if lhs._sequenceNumber != rhs._sequenceNumber {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securegcm_InitiatorHello: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".InitiatorHello"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "public_dh_key"),
2: .standard(proto: "protocol_version"),
]
public var isInitialized: Bool {
if let v = self._publicDhKey, !v.isInitialized {return false}
return true
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularMessageField(value: &self._publicDhKey) }()
case 2: try { try decoder.decodeSingularInt32Field(value: &self._protocolVersion) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._publicDhKey {
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
} }()
try { if let v = self._protocolVersion {
try visitor.visitSingularInt32Field(value: v, fieldNumber: 2)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securegcm_InitiatorHello, rhs: Securegcm_InitiatorHello) -> Bool {
if lhs._publicDhKey != rhs._publicDhKey {return false}
if lhs._protocolVersion != rhs._protocolVersion {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securegcm_ResponderHello: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ResponderHello"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "public_dh_key"),
2: .standard(proto: "protocol_version"),
]
public var isInitialized: Bool {
if let v = self._publicDhKey, !v.isInitialized {return false}
return true
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularMessageField(value: &self._publicDhKey) }()
case 2: try { try decoder.decodeSingularInt32Field(value: &self._protocolVersion) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._publicDhKey {
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
} }()
try { if let v = self._protocolVersion {
try visitor.visitSingularInt32Field(value: v, fieldNumber: 2)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securegcm_ResponderHello, rhs: Securegcm_ResponderHello) -> Bool {
if lhs._publicDhKey != rhs._publicDhKey {return false}
if lhs._protocolVersion != rhs._protocolVersion {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securegcm_EcPoint: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".EcPoint"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "curve"),
2: .same(proto: "x"),
3: .same(proto: "y"),
]
public var isInitialized: Bool {
if self._curve == nil {return false}
if self._x == nil {return false}
if self._y == nil {return false}
return true
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularEnumField(value: &self._curve) }()
case 2: try { try decoder.decodeSingularBytesField(value: &self._x) }()
case 3: try { try decoder.decodeSingularBytesField(value: &self._y) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._curve {
try visitor.visitSingularEnumField(value: v, fieldNumber: 1)
} }()
try { if let v = self._x {
try visitor.visitSingularBytesField(value: v, fieldNumber: 2)
} }()
try { if let v = self._y {
try visitor.visitSingularBytesField(value: v, fieldNumber: 3)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securegcm_EcPoint, rhs: Securegcm_EcPoint) -> Bool {
if lhs._curve != rhs._curve {return false}
if lhs._x != rhs._x {return false}
if lhs._y != rhs._y {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securegcm_SpakeHandshakeMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SpakeHandshakeMessage"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "flow_number"),
2: .standard(proto: "ec_point"),
3: .standard(proto: "hash_value"),
4: .same(proto: "payload"),
]
public var isInitialized: Bool {
if let v = self._ecPoint, !v.isInitialized {return false}
return true
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularInt32Field(value: &self._flowNumber) }()
case 2: try { try decoder.decodeSingularMessageField(value: &self._ecPoint) }()
case 3: try { try decoder.decodeSingularBytesField(value: &self._hashValue_p) }()
case 4: try { try decoder.decodeSingularBytesField(value: &self._payload) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._flowNumber {
try visitor.visitSingularInt32Field(value: v, fieldNumber: 1)
} }()
try { if let v = self._ecPoint {
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
} }()
try { if let v = self._hashValue_p {
try visitor.visitSingularBytesField(value: v, fieldNumber: 3)
} }()
try { if let v = self._payload {
try visitor.visitSingularBytesField(value: v, fieldNumber: 4)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securegcm_SpakeHandshakeMessage, rhs: Securegcm_SpakeHandshakeMessage) -> Bool {
if lhs._flowNumber != rhs._flowNumber {return false}
if lhs._ecPoint != rhs._ecPoint {return false}
if lhs._hashValue_p != rhs._hashValue_p {return false}
if lhs._payload != rhs._payload {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,951 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: securemessage.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
// Copyright 2020 Google LLC
//
// 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
//
// https://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.
// Proto definitions for SecureMessage format
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
/// Supported "signature" schemes (both symmetric key and public key based)
enum Securemessage_SigScheme: SwiftProtobuf.Enum {
typealias RawValue = Int
case hmacSha256 // = 1
case ecdsaP256Sha256 // = 2
/// Not recommended -- use ECDSA_P256_SHA256 instead
case rsa2048Sha256 // = 3
init() {
self = .hmacSha256
}
init?(rawValue: Int) {
switch rawValue {
case 1: self = .hmacSha256
case 2: self = .ecdsaP256Sha256
case 3: self = .rsa2048Sha256
default: return nil
}
}
var rawValue: Int {
switch self {
case .hmacSha256: return 1
case .ecdsaP256Sha256: return 2
case .rsa2048Sha256: return 3
}
}
}
#if swift(>=4.2)
extension Securemessage_SigScheme: CaseIterable {
// Support synthesized by the compiler.
}
#endif // swift(>=4.2)
/// Supported encryption schemes
enum Securemessage_EncScheme: SwiftProtobuf.Enum {
typealias RawValue = Int
/// No encryption
case none // = 1
case aes256Cbc // = 2
init() {
self = .none
}
init?(rawValue: Int) {
switch rawValue {
case 1: self = .none
case 2: self = .aes256Cbc
default: return nil
}
}
var rawValue: Int {
switch self {
case .none: return 1
case .aes256Cbc: return 2
}
}
}
#if swift(>=4.2)
extension Securemessage_EncScheme: CaseIterable {
// Support synthesized by the compiler.
}
#endif // swift(>=4.2)
/// A list of supported public key types
enum Securemessage_PublicKeyType: SwiftProtobuf.Enum {
typealias RawValue = Int
case ecP256 // = 1
case rsa2048 // = 2
/// 2048-bit MODP group 14, from RFC 3526
case dh2048Modp // = 3
init() {
self = .ecP256
}
init?(rawValue: Int) {
switch rawValue {
case 1: self = .ecP256
case 2: self = .rsa2048
case 3: self = .dh2048Modp
default: return nil
}
}
var rawValue: Int {
switch self {
case .ecP256: return 1
case .rsa2048: return 2
case .dh2048Modp: return 3
}
}
}
#if swift(>=4.2)
extension Securemessage_PublicKeyType: CaseIterable {
// Support synthesized by the compiler.
}
#endif // swift(>=4.2)
struct Securemessage_SecureMessage {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Must contain a HeaderAndBody message
var headerAndBody: Data {
get {return _headerAndBody ?? Data()}
set {_headerAndBody = newValue}
}
/// Returns true if `headerAndBody` has been explicitly set.
var hasHeaderAndBody: Bool {return self._headerAndBody != nil}
/// Clears the value of `headerAndBody`. Subsequent reads from it will return its default value.
mutating func clearHeaderAndBody() {self._headerAndBody = nil}
/// Signature of header_and_body
var signature: Data {
get {return _signature ?? Data()}
set {_signature = newValue}
}
/// Returns true if `signature` has been explicitly set.
var hasSignature: Bool {return self._signature != nil}
/// Clears the value of `signature`. Subsequent reads from it will return its default value.
mutating func clearSignature() {self._signature = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _headerAndBody: Data? = nil
fileprivate var _signature: Data? = nil
}
struct Securemessage_Header {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var signatureScheme: Securemessage_SigScheme {
get {return _signatureScheme ?? .hmacSha256}
set {_signatureScheme = newValue}
}
/// Returns true if `signatureScheme` has been explicitly set.
var hasSignatureScheme: Bool {return self._signatureScheme != nil}
/// Clears the value of `signatureScheme`. Subsequent reads from it will return its default value.
mutating func clearSignatureScheme() {self._signatureScheme = nil}
var encryptionScheme: Securemessage_EncScheme {
get {return _encryptionScheme ?? .none}
set {_encryptionScheme = newValue}
}
/// Returns true if `encryptionScheme` has been explicitly set.
var hasEncryptionScheme: Bool {return self._encryptionScheme != nil}
/// Clears the value of `encryptionScheme`. Subsequent reads from it will return its default value.
mutating func clearEncryptionScheme() {self._encryptionScheme = nil}
/// Identifies the verification key
var verificationKeyID: Data {
get {return _verificationKeyID ?? Data()}
set {_verificationKeyID = newValue}
}
/// Returns true if `verificationKeyID` has been explicitly set.
var hasVerificationKeyID: Bool {return self._verificationKeyID != nil}
/// Clears the value of `verificationKeyID`. Subsequent reads from it will return its default value.
mutating func clearVerificationKeyID() {self._verificationKeyID = nil}
/// Identifies the decryption key
var decryptionKeyID: Data {
get {return _decryptionKeyID ?? Data()}
set {_decryptionKeyID = newValue}
}
/// Returns true if `decryptionKeyID` has been explicitly set.
var hasDecryptionKeyID: Bool {return self._decryptionKeyID != nil}
/// Clears the value of `decryptionKeyID`. Subsequent reads from it will return its default value.
mutating func clearDecryptionKeyID() {self._decryptionKeyID = nil}
/// Encryption may use an IV
var iv: Data {
get {return _iv ?? Data()}
set {_iv = newValue}
}
/// Returns true if `iv` has been explicitly set.
var hasIv: Bool {return self._iv != nil}
/// Clears the value of `iv`. Subsequent reads from it will return its default value.
mutating func clearIv() {self._iv = nil}
/// Arbitrary per-protocol public data, to be sent with the plain-text header
var publicMetadata: Data {
get {return _publicMetadata ?? Data()}
set {_publicMetadata = newValue}
}
/// Returns true if `publicMetadata` has been explicitly set.
var hasPublicMetadata: Bool {return self._publicMetadata != nil}
/// Clears the value of `publicMetadata`. Subsequent reads from it will return its default value.
mutating func clearPublicMetadata() {self._publicMetadata = nil}
/// The length of some associated data this is not sent in this SecureMessage,
/// but which will be bound to the signature.
var associatedDataLength: UInt32 {
get {return _associatedDataLength ?? 0}
set {_associatedDataLength = newValue}
}
/// Returns true if `associatedDataLength` has been explicitly set.
var hasAssociatedDataLength: Bool {return self._associatedDataLength != nil}
/// Clears the value of `associatedDataLength`. Subsequent reads from it will return its default value.
mutating func clearAssociatedDataLength() {self._associatedDataLength = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _signatureScheme: Securemessage_SigScheme? = nil
fileprivate var _encryptionScheme: Securemessage_EncScheme? = nil
fileprivate var _verificationKeyID: Data? = nil
fileprivate var _decryptionKeyID: Data? = nil
fileprivate var _iv: Data? = nil
fileprivate var _publicMetadata: Data? = nil
fileprivate var _associatedDataLength: UInt32? = nil
}
struct Securemessage_HeaderAndBody {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Public data about this message (to be bound in the signature)
var header: Securemessage_Header {
get {return _header ?? Securemessage_Header()}
set {_header = newValue}
}
/// Returns true if `header` has been explicitly set.
var hasHeader: Bool {return self._header != nil}
/// Clears the value of `header`. Subsequent reads from it will return its default value.
mutating func clearHeader() {self._header = nil}
/// Payload data
var body: Data {
get {return _body ?? Data()}
set {_body = newValue}
}
/// Returns true if `body` has been explicitly set.
var hasBody: Bool {return self._body != nil}
/// Clears the value of `body`. Subsequent reads from it will return its default value.
mutating func clearBody() {self._body = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _header: Securemessage_Header? = nil
fileprivate var _body: Data? = nil
}
/// Must be kept wire-format compatible with HeaderAndBody. Provides the
/// SecureMessage code with a consistent wire-format representation that
/// remains stable irrespective of protobuf implementation choices. This
/// low-level representation of a HeaderAndBody should not be used by
/// any code outside of the SecureMessage library implementation/tests.
struct Securemessage_HeaderAndBodyInternal {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// A raw (wire-format) byte encoding of a Header, suitable for hashing
var header: Data {
get {return _header ?? Data()}
set {_header = newValue}
}
/// Returns true if `header` has been explicitly set.
var hasHeader: Bool {return self._header != nil}
/// Clears the value of `header`. Subsequent reads from it will return its default value.
mutating func clearHeader() {self._header = nil}
/// Payload data
var body: Data {
get {return _body ?? Data()}
set {_body = newValue}
}
/// Returns true if `body` has been explicitly set.
var hasBody: Bool {return self._body != nil}
/// Clears the value of `body`. Subsequent reads from it will return its default value.
mutating func clearBody() {self._body = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _header: Data? = nil
fileprivate var _body: Data? = nil
}
/// A convenience proto for encoding NIST P-256 elliptic curve public keys
struct Securemessage_EcP256PublicKey {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// x and y are encoded in big-endian two's complement (slightly wasteful)
/// Client MUST verify (x,y) is a valid point on NIST P256
var x: Data {
get {return _x ?? Data()}
set {_x = newValue}
}
/// Returns true if `x` has been explicitly set.
var hasX: Bool {return self._x != nil}
/// Clears the value of `x`. Subsequent reads from it will return its default value.
mutating func clearX() {self._x = nil}
var y: Data {
get {return _y ?? Data()}
set {_y = newValue}
}
/// Returns true if `y` has been explicitly set.
var hasY: Bool {return self._y != nil}
/// Clears the value of `y`. Subsequent reads from it will return its default value.
mutating func clearY() {self._y = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _x: Data? = nil
fileprivate var _y: Data? = nil
}
/// A convenience proto for encoding RSA public keys with small exponents
struct Securemessage_SimpleRsaPublicKey {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Encoded in big-endian two's complement
var n: Data {
get {return _n ?? Data()}
set {_n = newValue}
}
/// Returns true if `n` has been explicitly set.
var hasN: Bool {return self._n != nil}
/// Clears the value of `n`. Subsequent reads from it will return its default value.
mutating func clearN() {self._n = nil}
var e: Int32 {
get {return _e ?? 65537}
set {_e = newValue}
}
/// Returns true if `e` has been explicitly set.
var hasE: Bool {return self._e != nil}
/// Clears the value of `e`. Subsequent reads from it will return its default value.
mutating func clearE() {self._e = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _n: Data? = nil
fileprivate var _e: Int32? = nil
}
/// A convenience proto for encoding Diffie-Hellman public keys,
/// for use only when Elliptic Curve based key exchanges are not possible.
/// (Note that the group parameters must be specified separately)
struct Securemessage_DhPublicKey {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Big-endian two's complement encoded group element
var y: Data {
get {return _y ?? Data()}
set {_y = newValue}
}
/// Returns true if `y` has been explicitly set.
var hasY: Bool {return self._y != nil}
/// Clears the value of `y`. Subsequent reads from it will return its default value.
mutating func clearY() {self._y = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _y: Data? = nil
}
struct Securemessage_GenericPublicKey {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var type: Securemessage_PublicKeyType {
get {return _type ?? .ecP256}
set {_type = newValue}
}
/// Returns true if `type` has been explicitly set.
var hasType: Bool {return self._type != nil}
/// Clears the value of `type`. Subsequent reads from it will return its default value.
mutating func clearType() {self._type = nil}
var ecP256PublicKey: Securemessage_EcP256PublicKey {
get {return _ecP256PublicKey ?? Securemessage_EcP256PublicKey()}
set {_ecP256PublicKey = newValue}
}
/// Returns true if `ecP256PublicKey` has been explicitly set.
var hasEcP256PublicKey: Bool {return self._ecP256PublicKey != nil}
/// Clears the value of `ecP256PublicKey`. Subsequent reads from it will return its default value.
mutating func clearEcP256PublicKey() {self._ecP256PublicKey = nil}
var rsa2048PublicKey: Securemessage_SimpleRsaPublicKey {
get {return _rsa2048PublicKey ?? Securemessage_SimpleRsaPublicKey()}
set {_rsa2048PublicKey = newValue}
}
/// Returns true if `rsa2048PublicKey` has been explicitly set.
var hasRsa2048PublicKey: Bool {return self._rsa2048PublicKey != nil}
/// Clears the value of `rsa2048PublicKey`. Subsequent reads from it will return its default value.
mutating func clearRsa2048PublicKey() {self._rsa2048PublicKey = nil}
/// Use only as a last resort
var dh2048PublicKey: Securemessage_DhPublicKey {
get {return _dh2048PublicKey ?? Securemessage_DhPublicKey()}
set {_dh2048PublicKey = newValue}
}
/// Returns true if `dh2048PublicKey` has been explicitly set.
var hasDh2048PublicKey: Bool {return self._dh2048PublicKey != nil}
/// Clears the value of `dh2048PublicKey`. Subsequent reads from it will return its default value.
mutating func clearDh2048PublicKey() {self._dh2048PublicKey = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _type: Securemessage_PublicKeyType? = nil
fileprivate var _ecP256PublicKey: Securemessage_EcP256PublicKey? = nil
fileprivate var _rsa2048PublicKey: Securemessage_SimpleRsaPublicKey? = nil
fileprivate var _dh2048PublicKey: Securemessage_DhPublicKey? = nil
}
#if swift(>=5.5) && canImport(_Concurrency)
extension Securemessage_SigScheme: @unchecked Sendable {}
extension Securemessage_EncScheme: @unchecked Sendable {}
extension Securemessage_PublicKeyType: @unchecked Sendable {}
extension Securemessage_SecureMessage: @unchecked Sendable {}
extension Securemessage_Header: @unchecked Sendable {}
extension Securemessage_HeaderAndBody: @unchecked Sendable {}
extension Securemessage_HeaderAndBodyInternal: @unchecked Sendable {}
extension Securemessage_EcP256PublicKey: @unchecked Sendable {}
extension Securemessage_SimpleRsaPublicKey: @unchecked Sendable {}
extension Securemessage_DhPublicKey: @unchecked Sendable {}
extension Securemessage_GenericPublicKey: @unchecked Sendable {}
#endif // swift(>=5.5) && canImport(_Concurrency)
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "securemessage"
extension Securemessage_SigScheme: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "HMAC_SHA256"),
2: .same(proto: "ECDSA_P256_SHA256"),
3: .same(proto: "RSA2048_SHA256"),
]
}
extension Securemessage_EncScheme: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "NONE"),
2: .same(proto: "AES_256_CBC"),
]
}
extension Securemessage_PublicKeyType: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "EC_P256"),
2: .same(proto: "RSA2048"),
3: .same(proto: "DH2048_MODP"),
]
}
extension Securemessage_SecureMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SecureMessage"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "header_and_body"),
2: .same(proto: "signature"),
]
public var isInitialized: Bool {
if self._headerAndBody == nil {return false}
if self._signature == nil {return false}
return true
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularBytesField(value: &self._headerAndBody) }()
case 2: try { try decoder.decodeSingularBytesField(value: &self._signature) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._headerAndBody {
try visitor.visitSingularBytesField(value: v, fieldNumber: 1)
} }()
try { if let v = self._signature {
try visitor.visitSingularBytesField(value: v, fieldNumber: 2)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securemessage_SecureMessage, rhs: Securemessage_SecureMessage) -> Bool {
if lhs._headerAndBody != rhs._headerAndBody {return false}
if lhs._signature != rhs._signature {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securemessage_Header: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Header"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "signature_scheme"),
2: .standard(proto: "encryption_scheme"),
3: .standard(proto: "verification_key_id"),
4: .standard(proto: "decryption_key_id"),
5: .same(proto: "iv"),
6: .standard(proto: "public_metadata"),
7: .standard(proto: "associated_data_length"),
]
public var isInitialized: Bool {
if self._signatureScheme == nil {return false}
if self._encryptionScheme == nil {return false}
return true
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularEnumField(value: &self._signatureScheme) }()
case 2: try { try decoder.decodeSingularEnumField(value: &self._encryptionScheme) }()
case 3: try { try decoder.decodeSingularBytesField(value: &self._verificationKeyID) }()
case 4: try { try decoder.decodeSingularBytesField(value: &self._decryptionKeyID) }()
case 5: try { try decoder.decodeSingularBytesField(value: &self._iv) }()
case 6: try { try decoder.decodeSingularBytesField(value: &self._publicMetadata) }()
case 7: try { try decoder.decodeSingularUInt32Field(value: &self._associatedDataLength) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._signatureScheme {
try visitor.visitSingularEnumField(value: v, fieldNumber: 1)
} }()
try { if let v = self._encryptionScheme {
try visitor.visitSingularEnumField(value: v, fieldNumber: 2)
} }()
try { if let v = self._verificationKeyID {
try visitor.visitSingularBytesField(value: v, fieldNumber: 3)
} }()
try { if let v = self._decryptionKeyID {
try visitor.visitSingularBytesField(value: v, fieldNumber: 4)
} }()
try { if let v = self._iv {
try visitor.visitSingularBytesField(value: v, fieldNumber: 5)
} }()
try { if let v = self._publicMetadata {
try visitor.visitSingularBytesField(value: v, fieldNumber: 6)
} }()
try { if let v = self._associatedDataLength {
try visitor.visitSingularUInt32Field(value: v, fieldNumber: 7)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securemessage_Header, rhs: Securemessage_Header) -> Bool {
if lhs._signatureScheme != rhs._signatureScheme {return false}
if lhs._encryptionScheme != rhs._encryptionScheme {return false}
if lhs._verificationKeyID != rhs._verificationKeyID {return false}
if lhs._decryptionKeyID != rhs._decryptionKeyID {return false}
if lhs._iv != rhs._iv {return false}
if lhs._publicMetadata != rhs._publicMetadata {return false}
if lhs._associatedDataLength != rhs._associatedDataLength {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securemessage_HeaderAndBody: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".HeaderAndBody"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "header"),
2: .same(proto: "body"),
]
public var isInitialized: Bool {
if self._header == nil {return false}
if self._body == nil {return false}
if let v = self._header, !v.isInitialized {return false}
return true
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularMessageField(value: &self._header) }()
case 2: try { try decoder.decodeSingularBytesField(value: &self._body) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._header {
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
} }()
try { if let v = self._body {
try visitor.visitSingularBytesField(value: v, fieldNumber: 2)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securemessage_HeaderAndBody, rhs: Securemessage_HeaderAndBody) -> Bool {
if lhs._header != rhs._header {return false}
if lhs._body != rhs._body {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securemessage_HeaderAndBodyInternal: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".HeaderAndBodyInternal"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "header"),
2: .same(proto: "body"),
]
public var isInitialized: Bool {
if self._header == nil {return false}
if self._body == nil {return false}
return true
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularBytesField(value: &self._header) }()
case 2: try { try decoder.decodeSingularBytesField(value: &self._body) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._header {
try visitor.visitSingularBytesField(value: v, fieldNumber: 1)
} }()
try { if let v = self._body {
try visitor.visitSingularBytesField(value: v, fieldNumber: 2)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securemessage_HeaderAndBodyInternal, rhs: Securemessage_HeaderAndBodyInternal) -> Bool {
if lhs._header != rhs._header {return false}
if lhs._body != rhs._body {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securemessage_EcP256PublicKey: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".EcP256PublicKey"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "x"),
2: .same(proto: "y"),
]
public var isInitialized: Bool {
if self._x == nil {return false}
if self._y == nil {return false}
return true
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularBytesField(value: &self._x) }()
case 2: try { try decoder.decodeSingularBytesField(value: &self._y) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._x {
try visitor.visitSingularBytesField(value: v, fieldNumber: 1)
} }()
try { if let v = self._y {
try visitor.visitSingularBytesField(value: v, fieldNumber: 2)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securemessage_EcP256PublicKey, rhs: Securemessage_EcP256PublicKey) -> Bool {
if lhs._x != rhs._x {return false}
if lhs._y != rhs._y {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securemessage_SimpleRsaPublicKey: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SimpleRsaPublicKey"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "n"),
2: .same(proto: "e"),
]
public var isInitialized: Bool {
if self._n == nil {return false}
return true
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularBytesField(value: &self._n) }()
case 2: try { try decoder.decodeSingularInt32Field(value: &self._e) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._n {
try visitor.visitSingularBytesField(value: v, fieldNumber: 1)
} }()
try { if let v = self._e {
try visitor.visitSingularInt32Field(value: v, fieldNumber: 2)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securemessage_SimpleRsaPublicKey, rhs: Securemessage_SimpleRsaPublicKey) -> Bool {
if lhs._n != rhs._n {return false}
if lhs._e != rhs._e {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securemessage_DhPublicKey: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".DhPublicKey"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "y"),
]
public var isInitialized: Bool {
if self._y == nil {return false}
return true
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularBytesField(value: &self._y) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._y {
try visitor.visitSingularBytesField(value: v, fieldNumber: 1)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securemessage_DhPublicKey, rhs: Securemessage_DhPublicKey) -> Bool {
if lhs._y != rhs._y {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securemessage_GenericPublicKey: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".GenericPublicKey"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "type"),
2: .standard(proto: "ec_p256_public_key"),
3: .standard(proto: "rsa2048_public_key"),
4: .standard(proto: "dh2048_public_key"),
]
public var isInitialized: Bool {
if self._type == nil {return false}
if let v = self._ecP256PublicKey, !v.isInitialized {return false}
if let v = self._rsa2048PublicKey, !v.isInitialized {return false}
if let v = self._dh2048PublicKey, !v.isInitialized {return false}
return true
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularEnumField(value: &self._type) }()
case 2: try { try decoder.decodeSingularMessageField(value: &self._ecP256PublicKey) }()
case 3: try { try decoder.decodeSingularMessageField(value: &self._rsa2048PublicKey) }()
case 4: try { try decoder.decodeSingularMessageField(value: &self._dh2048PublicKey) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._type {
try visitor.visitSingularEnumField(value: v, fieldNumber: 1)
} }()
try { if let v = self._ecP256PublicKey {
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
} }()
try { if let v = self._rsa2048PublicKey {
try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
} }()
try { if let v = self._dh2048PublicKey {
try visitor.visitSingularMessageField(value: v, fieldNumber: 4)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securemessage_GenericPublicKey, rhs: Securemessage_GenericPublicKey) -> Bool {
if lhs._type != rhs._type {return false}
if lhs._ecP256PublicKey != rhs._ecP256PublicKey {return false}
if lhs._rsa2048PublicKey != rhs._rsa2048PublicKey {return false}
if lhs._dh2048PublicKey != rhs._dh2048PublicKey {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

View File

@@ -0,0 +1,735 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: ukey.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
// Copyright 2020 Google LLC
//
// 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
//
// https://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
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
enum Securegcm_Ukey2HandshakeCipher: SwiftProtobuf.Enum {
typealias RawValue = Int
case reserved // = 0
/// NIST P-256 used for ECDH, SHA512 used for
case p256Sha512 // = 100
/// commitment
case curve25519Sha512 // = 200
init() {
self = .reserved
}
init?(rawValue: Int) {
switch rawValue {
case 0: self = .reserved
case 100: self = .p256Sha512
case 200: self = .curve25519Sha512
default: return nil
}
}
var rawValue: Int {
switch self {
case .reserved: return 0
case .p256Sha512: return 100
case .curve25519Sha512: return 200
}
}
}
#if swift(>=4.2)
extension Securegcm_Ukey2HandshakeCipher: CaseIterable {
// Support synthesized by the compiler.
}
#endif // swift(>=4.2)
struct Securegcm_Ukey2Message {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Identifies message type
var messageType: Securegcm_Ukey2Message.TypeEnum {
get {return _messageType ?? .unknownDoNotUse}
set {_messageType = newValue}
}
/// Returns true if `messageType` has been explicitly set.
var hasMessageType: Bool {return self._messageType != nil}
/// Clears the value of `messageType`. Subsequent reads from it will return its default value.
mutating func clearMessageType() {self._messageType = nil}
/// Actual message, to be parsed according to
var messageData: Data {
get {return _messageData ?? Data()}
set {_messageData = newValue}
}
/// Returns true if `messageData` has been explicitly set.
var hasMessageData: Bool {return self._messageData != nil}
/// Clears the value of `messageData`. Subsequent reads from it will return its default value.
mutating func clearMessageData() {self._messageData = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
enum TypeEnum: SwiftProtobuf.Enum {
typealias RawValue = Int
case unknownDoNotUse // = 0
case alert // = 1
case clientInit // = 2
case serverInit // = 3
case clientFinish // = 4
init() {
self = .unknownDoNotUse
}
init?(rawValue: Int) {
switch rawValue {
case 0: self = .unknownDoNotUse
case 1: self = .alert
case 2: self = .clientInit
case 3: self = .serverInit
case 4: self = .clientFinish
default: return nil
}
}
var rawValue: Int {
switch self {
case .unknownDoNotUse: return 0
case .alert: return 1
case .clientInit: return 2
case .serverInit: return 3
case .clientFinish: return 4
}
}
}
init() {}
fileprivate var _messageType: Securegcm_Ukey2Message.TypeEnum? = nil
fileprivate var _messageData: Data? = nil
}
#if swift(>=4.2)
extension Securegcm_Ukey2Message.TypeEnum: CaseIterable {
// Support synthesized by the compiler.
}
#endif // swift(>=4.2)
struct Securegcm_Ukey2Alert {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var type: Securegcm_Ukey2Alert.AlertType {
get {return _type ?? .badMessage}
set {_type = newValue}
}
/// Returns true if `type` has been explicitly set.
var hasType: Bool {return self._type != nil}
/// Clears the value of `type`. Subsequent reads from it will return its default value.
mutating func clearType() {self._type = nil}
var errorMessage: String {
get {return _errorMessage ?? String()}
set {_errorMessage = newValue}
}
/// Returns true if `errorMessage` has been explicitly set.
var hasErrorMessage: Bool {return self._errorMessage != nil}
/// Clears the value of `errorMessage`. Subsequent reads from it will return its default value.
mutating func clearErrorMessage() {self._errorMessage = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
enum AlertType: SwiftProtobuf.Enum {
typealias RawValue = Int
/// Framing errors
case badMessage // = 1
/// message_type has an undefined value
case badMessageType // = 2
/// message_type received does not correspond to
case incorrectMessage // = 3
/// expected type at this stage of the protocol
case badMessageData // = 4
/// ClientInit and ServerInit errors
case badVersion // = 100
/// suitable version to speak with client.
case badRandom // = 101
/// length
case badHandshakeCipher // = 102
/// The next protocol is missing, unknown, or
case badNextProtocol // = 103
/// unsupported
case badPublicKey // = 104
/// Other errors
case internalError // = 200
init() {
self = .badMessage
}
init?(rawValue: Int) {
switch rawValue {
case 1: self = .badMessage
case 2: self = .badMessageType
case 3: self = .incorrectMessage
case 4: self = .badMessageData
case 100: self = .badVersion
case 101: self = .badRandom
case 102: self = .badHandshakeCipher
case 103: self = .badNextProtocol
case 104: self = .badPublicKey
case 200: self = .internalError
default: return nil
}
}
var rawValue: Int {
switch self {
case .badMessage: return 1
case .badMessageType: return 2
case .incorrectMessage: return 3
case .badMessageData: return 4
case .badVersion: return 100
case .badRandom: return 101
case .badHandshakeCipher: return 102
case .badNextProtocol: return 103
case .badPublicKey: return 104
case .internalError: return 200
}
}
}
init() {}
fileprivate var _type: Securegcm_Ukey2Alert.AlertType? = nil
fileprivate var _errorMessage: String? = nil
}
#if swift(>=4.2)
extension Securegcm_Ukey2Alert.AlertType: CaseIterable {
// Support synthesized by the compiler.
}
#endif // swift(>=4.2)
struct Securegcm_Ukey2ClientInit {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// highest supported version for rollback
var version: Int32 {
get {return _version ?? 0}
set {_version = newValue}
}
/// Returns true if `version` has been explicitly set.
var hasVersion: Bool {return self._version != nil}
/// Clears the value of `version`. Subsequent reads from it will return its default value.
mutating func clearVersion() {self._version = nil}
/// protection
var random: Data {
get {return _random ?? Data()}
set {_random = newValue}
}
/// Returns true if `random` has been explicitly set.
var hasRandom: Bool {return self._random != nil}
/// Clears the value of `random`. Subsequent reads from it will return its default value.
mutating func clearRandom() {self._random = nil}
var cipherCommitments: [Securegcm_Ukey2ClientInit.CipherCommitment] = []
/// Next protocol that the client wants to speak.
var nextProtocol: String {
get {return _nextProtocol ?? String()}
set {_nextProtocol = newValue}
}
/// Returns true if `nextProtocol` has been explicitly set.
var hasNextProtocol: Bool {return self._nextProtocol != nil}
/// Clears the value of `nextProtocol`. Subsequent reads from it will return its default value.
mutating func clearNextProtocol() {self._nextProtocol = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
/// One commitment (hash of ClientFinished containing public key) per supported
/// cipher
struct CipherCommitment {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var handshakeCipher: Securegcm_Ukey2HandshakeCipher {
get {return _handshakeCipher ?? .reserved}
set {_handshakeCipher = newValue}
}
/// Returns true if `handshakeCipher` has been explicitly set.
var hasHandshakeCipher: Bool {return self._handshakeCipher != nil}
/// Clears the value of `handshakeCipher`. Subsequent reads from it will return its default value.
mutating func clearHandshakeCipher() {self._handshakeCipher = nil}
var commitment: Data {
get {return _commitment ?? Data()}
set {_commitment = newValue}
}
/// Returns true if `commitment` has been explicitly set.
var hasCommitment: Bool {return self._commitment != nil}
/// Clears the value of `commitment`. Subsequent reads from it will return its default value.
mutating func clearCommitment() {self._commitment = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _handshakeCipher: Securegcm_Ukey2HandshakeCipher? = nil
fileprivate var _commitment: Data? = nil
}
init() {}
fileprivate var _version: Int32? = nil
fileprivate var _random: Data? = nil
fileprivate var _nextProtocol: String? = nil
}
struct Securegcm_Ukey2ServerInit {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// highest supported version for rollback
var version: Int32 {
get {return _version ?? 0}
set {_version = newValue}
}
/// Returns true if `version` has been explicitly set.
var hasVersion: Bool {return self._version != nil}
/// Clears the value of `version`. Subsequent reads from it will return its default value.
mutating func clearVersion() {self._version = nil}
/// protection
var random: Data {
get {return _random ?? Data()}
set {_random = newValue}
}
/// Returns true if `random` has been explicitly set.
var hasRandom: Bool {return self._random != nil}
/// Clears the value of `random`. Subsequent reads from it will return its default value.
mutating func clearRandom() {self._random = nil}
/// Selected Cipher and corresponding public key
var handshakeCipher: Securegcm_Ukey2HandshakeCipher {
get {return _handshakeCipher ?? .reserved}
set {_handshakeCipher = newValue}
}
/// Returns true if `handshakeCipher` has been explicitly set.
var hasHandshakeCipher: Bool {return self._handshakeCipher != nil}
/// Clears the value of `handshakeCipher`. Subsequent reads from it will return its default value.
mutating func clearHandshakeCipher() {self._handshakeCipher = nil}
var publicKey: Data {
get {return _publicKey ?? Data()}
set {_publicKey = newValue}
}
/// Returns true if `publicKey` has been explicitly set.
var hasPublicKey: Bool {return self._publicKey != nil}
/// Clears the value of `publicKey`. Subsequent reads from it will return its default value.
mutating func clearPublicKey() {self._publicKey = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _version: Int32? = nil
fileprivate var _random: Data? = nil
fileprivate var _handshakeCipher: Securegcm_Ukey2HandshakeCipher? = nil
fileprivate var _publicKey: Data? = nil
}
struct Securegcm_Ukey2ClientFinished {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// public key matching selected handshake
var publicKey: Data {
get {return _publicKey ?? Data()}
set {_publicKey = newValue}
}
/// Returns true if `publicKey` has been explicitly set.
var hasPublicKey: Bool {return self._publicKey != nil}
/// Clears the value of `publicKey`. Subsequent reads from it will return its default value.
mutating func clearPublicKey() {self._publicKey = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _publicKey: Data? = nil
}
#if swift(>=5.5) && canImport(_Concurrency)
extension Securegcm_Ukey2HandshakeCipher: @unchecked Sendable {}
extension Securegcm_Ukey2Message: @unchecked Sendable {}
extension Securegcm_Ukey2Message.TypeEnum: @unchecked Sendable {}
extension Securegcm_Ukey2Alert: @unchecked Sendable {}
extension Securegcm_Ukey2Alert.AlertType: @unchecked Sendable {}
extension Securegcm_Ukey2ClientInit: @unchecked Sendable {}
extension Securegcm_Ukey2ClientInit.CipherCommitment: @unchecked Sendable {}
extension Securegcm_Ukey2ServerInit: @unchecked Sendable {}
extension Securegcm_Ukey2ClientFinished: @unchecked Sendable {}
#endif // swift(>=5.5) && canImport(_Concurrency)
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "securegcm"
extension Securegcm_Ukey2HandshakeCipher: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "RESERVED"),
100: .same(proto: "P256_SHA512"),
200: .same(proto: "CURVE25519_SHA512"),
]
}
extension Securegcm_Ukey2Message: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Ukey2Message"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "message_type"),
2: .standard(proto: "message_data"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularEnumField(value: &self._messageType) }()
case 2: try { try decoder.decodeSingularBytesField(value: &self._messageData) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._messageType {
try visitor.visitSingularEnumField(value: v, fieldNumber: 1)
} }()
try { if let v = self._messageData {
try visitor.visitSingularBytesField(value: v, fieldNumber: 2)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securegcm_Ukey2Message, rhs: Securegcm_Ukey2Message) -> Bool {
if lhs._messageType != rhs._messageType {return false}
if lhs._messageData != rhs._messageData {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securegcm_Ukey2Message.TypeEnum: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "UNKNOWN_DO_NOT_USE"),
1: .same(proto: "ALERT"),
2: .same(proto: "CLIENT_INIT"),
3: .same(proto: "SERVER_INIT"),
4: .same(proto: "CLIENT_FINISH"),
]
}
extension Securegcm_Ukey2Alert: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Ukey2Alert"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "type"),
2: .standard(proto: "error_message"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularEnumField(value: &self._type) }()
case 2: try { try decoder.decodeSingularStringField(value: &self._errorMessage) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._type {
try visitor.visitSingularEnumField(value: v, fieldNumber: 1)
} }()
try { if let v = self._errorMessage {
try visitor.visitSingularStringField(value: v, fieldNumber: 2)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securegcm_Ukey2Alert, rhs: Securegcm_Ukey2Alert) -> Bool {
if lhs._type != rhs._type {return false}
if lhs._errorMessage != rhs._errorMessage {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securegcm_Ukey2Alert.AlertType: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "BAD_MESSAGE"),
2: .same(proto: "BAD_MESSAGE_TYPE"),
3: .same(proto: "INCORRECT_MESSAGE"),
4: .same(proto: "BAD_MESSAGE_DATA"),
100: .same(proto: "BAD_VERSION"),
101: .same(proto: "BAD_RANDOM"),
102: .same(proto: "BAD_HANDSHAKE_CIPHER"),
103: .same(proto: "BAD_NEXT_PROTOCOL"),
104: .same(proto: "BAD_PUBLIC_KEY"),
200: .same(proto: "INTERNAL_ERROR"),
]
}
extension Securegcm_Ukey2ClientInit: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Ukey2ClientInit"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "version"),
2: .same(proto: "random"),
3: .standard(proto: "cipher_commitments"),
4: .standard(proto: "next_protocol"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularInt32Field(value: &self._version) }()
case 2: try { try decoder.decodeSingularBytesField(value: &self._random) }()
case 3: try { try decoder.decodeRepeatedMessageField(value: &self.cipherCommitments) }()
case 4: try { try decoder.decodeSingularStringField(value: &self._nextProtocol) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._version {
try visitor.visitSingularInt32Field(value: v, fieldNumber: 1)
} }()
try { if let v = self._random {
try visitor.visitSingularBytesField(value: v, fieldNumber: 2)
} }()
if !self.cipherCommitments.isEmpty {
try visitor.visitRepeatedMessageField(value: self.cipherCommitments, fieldNumber: 3)
}
try { if let v = self._nextProtocol {
try visitor.visitSingularStringField(value: v, fieldNumber: 4)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securegcm_Ukey2ClientInit, rhs: Securegcm_Ukey2ClientInit) -> Bool {
if lhs._version != rhs._version {return false}
if lhs._random != rhs._random {return false}
if lhs.cipherCommitments != rhs.cipherCommitments {return false}
if lhs._nextProtocol != rhs._nextProtocol {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securegcm_Ukey2ClientInit.CipherCommitment: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = Securegcm_Ukey2ClientInit.protoMessageName + ".CipherCommitment"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "handshake_cipher"),
2: .same(proto: "commitment"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularEnumField(value: &self._handshakeCipher) }()
case 2: try { try decoder.decodeSingularBytesField(value: &self._commitment) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._handshakeCipher {
try visitor.visitSingularEnumField(value: v, fieldNumber: 1)
} }()
try { if let v = self._commitment {
try visitor.visitSingularBytesField(value: v, fieldNumber: 2)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securegcm_Ukey2ClientInit.CipherCommitment, rhs: Securegcm_Ukey2ClientInit.CipherCommitment) -> Bool {
if lhs._handshakeCipher != rhs._handshakeCipher {return false}
if lhs._commitment != rhs._commitment {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securegcm_Ukey2ServerInit: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Ukey2ServerInit"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "version"),
2: .same(proto: "random"),
3: .standard(proto: "handshake_cipher"),
4: .standard(proto: "public_key"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularInt32Field(value: &self._version) }()
case 2: try { try decoder.decodeSingularBytesField(value: &self._random) }()
case 3: try { try decoder.decodeSingularEnumField(value: &self._handshakeCipher) }()
case 4: try { try decoder.decodeSingularBytesField(value: &self._publicKey) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._version {
try visitor.visitSingularInt32Field(value: v, fieldNumber: 1)
} }()
try { if let v = self._random {
try visitor.visitSingularBytesField(value: v, fieldNumber: 2)
} }()
try { if let v = self._handshakeCipher {
try visitor.visitSingularEnumField(value: v, fieldNumber: 3)
} }()
try { if let v = self._publicKey {
try visitor.visitSingularBytesField(value: v, fieldNumber: 4)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securegcm_Ukey2ServerInit, rhs: Securegcm_Ukey2ServerInit) -> Bool {
if lhs._version != rhs._version {return false}
if lhs._random != rhs._random {return false}
if lhs._handshakeCipher != rhs._handshakeCipher {return false}
if lhs._publicKey != rhs._publicKey {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Securegcm_Ukey2ClientFinished: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Ukey2ClientFinished"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "public_key"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularBytesField(value: &self._publicKey) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._publicKey {
try visitor.visitSingularBytesField(value: v, fieldNumber: 1)
} }()
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Securegcm_Ukey2ClientFinished, rhs: Securegcm_Ukey2ClientFinished) -> Bool {
if lhs._publicKey != rhs._publicKey {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
// Copyright 2020 Google LLC
//
// 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
//
// https://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.
syntax = "proto2";
package securegcm;
import "securemessage.proto";
option optimize_for = LITE_RUNTIME;
option java_package = "com.google.security.cryptauth.lib.securegcm";
option java_outer_classname = "DeviceToDeviceMessagesProto";
option objc_class_prefix = "SGCM";
// Used by protocols between devices
message DeviceToDeviceMessage {
// the payload of the message
optional bytes message = 1;
// the sequence number of the message - must be increasing.
optional int32 sequence_number = 2;
}
// sent as the first message from initiator to responder
// in an unauthenticated Diffie-Hellman Key Exchange
message InitiatorHello {
// The session public key to send to the responder
optional securemessage.GenericPublicKey public_dh_key = 1;
// The protocol version
optional int32 protocol_version = 2 [default = 0];
}
// sent inside the header of the first message from the responder to the
// initiator in an unauthenticated Diffie-Hellman Key Exchange
message ResponderHello {
// The session public key to send to the initiator
optional securemessage.GenericPublicKey public_dh_key = 1;
// The protocol version
optional int32 protocol_version = 2 [default = 0];
}
// Type of curve
enum Curve { ED_25519 = 1; }
// A convenience proto for encoding curve points in affine representation
message EcPoint {
required Curve curve = 1;
// x and y are encoded in big-endian two's complement
// client MUST verify (x,y) is a valid point on the specified curve
required bytes x = 2;
required bytes y = 3;
}
message SpakeHandshakeMessage {
// Each flow in the protocol bumps this counter
optional int32 flow_number = 1;
// Some (but not all) SPAKE flows send a point on an elliptic curve
optional EcPoint ec_point = 2;
// Some (but not all) SPAKE flows send a hash value
optional bytes hash_value = 3;
// The last flow of a SPAKE protocol can send an optional payload,
// since the key exchange is already complete on the sender's side.
optional bytes payload = 4;
}

View File

@@ -0,0 +1,403 @@
// Copyright 2020 Google LLC
//
// 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
//
// https://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.
syntax = "proto2";
package location.nearby.connections;
option optimize_for = LITE_RUNTIME;
option java_outer_classname = "OfflineWireFormatsProto";
option java_package = "com.google.location.nearby.connections.proto";
option objc_class_prefix = "GNCP";
message OfflineFrame {
enum Version {
UNKNOWN_VERSION = 0;
V1 = 1;
}
optional Version version = 1;
// Right now there's only 1 version, but if there are more, exactly one of
// the following fields will be set.
optional V1Frame v1 = 2;
}
message V1Frame {
enum FrameType {
UNKNOWN_FRAME_TYPE = 0;
CONNECTION_REQUEST = 1;
CONNECTION_RESPONSE = 2;
PAYLOAD_TRANSFER = 3;
BANDWIDTH_UPGRADE_NEGOTIATION = 4;
KEEP_ALIVE = 5;
DISCONNECTION = 6;
PAIRED_KEY_ENCRYPTION = 7;
}
optional FrameType type = 1;
// Exactly one of the following fields will be set.
optional ConnectionRequestFrame connection_request = 2;
optional ConnectionResponseFrame connection_response = 3;
optional PayloadTransferFrame payload_transfer = 4;
optional BandwidthUpgradeNegotiationFrame bandwidth_upgrade_negotiation = 5;
optional KeepAliveFrame keep_alive = 6;
optional DisconnectionFrame disconnection = 7;
optional PairedKeyEncryptionFrame paired_key_encryption = 8;
}
message ConnectionRequestFrame {
// Should always match cs/symbol:location.nearby.proto.connections.Medium
// LINT.IfChange
enum Medium {
UNKNOWN_MEDIUM = 0;
MDNS = 1 [deprecated = true];
BLUETOOTH = 2;
WIFI_HOTSPOT = 3;
BLE = 4;
WIFI_LAN = 5;
WIFI_AWARE = 6;
NFC = 7;
WIFI_DIRECT = 8;
WEB_RTC = 9;
BLE_L2CAP = 10;
USB = 11;
}
// LINT.ThenChange(//depot/google3/third_party/nearby/proto/connections_enums.proto)
optional string endpoint_id = 1;
optional string endpoint_name = 2;
optional bytes handshake_data = 3;
// A random number generated for each outgoing connection that is presently
// used to act as a tiebreaker when 2 devices connect to each other
// simultaneously; this can also be used for other initialization-scoped
// things in the future.
optional int32 nonce = 4;
// The mediums this device supports upgrading to. This list should be filtered
// by both the strategy and this device's individual limitations.
repeated Medium mediums = 5;
optional bytes endpoint_info = 6;
optional MediumMetadata medium_metadata = 7;
optional int32 keep_alive_interval_millis = 8;
optional int32 keep_alive_timeout_millis = 9;
// The type of {@link Device} object.
optional int32 device_type = 10 [default = 0];
// The bytes of serialized {@link Device} object.
optional bytes device_info = 11;
}
message ConnectionResponseFrame {
// This doesn't need to send back endpoint_id and endpoint_name (like
// the ConnectionRequestFrame does) because those have already been
// transmitted out-of-band, at the time this endpoint was discovered.
// One of:
//
// - ConnectionsStatusCodes.STATUS_OK
// - ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED.
optional int32 status = 1 [deprecated = true];
optional bytes handshake_data = 2;
// Used to replace the status integer parameter with a meaningful enum item.
// Map ConnectionsStatusCodes.STATUS_OK to ACCEPT and
// ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED to REJECT.
// Flag: connection_replace_status_with_response_connectionResponseFrame
enum ResponseStatus {
UNKNOWN_RESPONSE_STATUS = 0;
ACCEPT = 1;
REJECT = 2;
}
optional ResponseStatus response = 3;
optional OsInfo os_info = 4;
// A bitmask value to indicate which medium supports Multiplex transmission
// feature. Each supporting medium could utilize one bit starting from the
// least significant bit in this field. eq. BT utilizes the LSB bit which 0x01
// means bt supports multiplex while 0x00 means not. Refer to ClientProxy.java
// for the bit usages.
optional int32 multiplex_socket_bitmask = 5;
optional int32 nearby_connections_version = 6;
}
message PayloadTransferFrame {
enum PacketType {
UNKNOWN_PACKET_TYPE = 0;
DATA = 1;
CONTROL = 2;
}
message PayloadHeader {
enum PayloadType {
UNKNOWN_PAYLOAD_TYPE = 0;
BYTES = 1;
FILE = 2;
STREAM = 3;
}
optional int64 id = 1;
optional PayloadType type = 2;
optional int64 total_size = 3;
optional bool is_sensitive = 4;
optional string file_name = 5;
optional string parent_folder = 6;
}
// Accompanies DATA packets.
message PayloadChunk {
enum Flags {
LAST_CHUNK = 0x1;
}
optional int32 flags = 1;
optional int64 offset = 2;
optional bytes body = 3;
}
// Accompanies CONTROL packets.
message ControlMessage {
enum EventType {
UNKNOWN_EVENT_TYPE = 0;
PAYLOAD_ERROR = 1;
PAYLOAD_CANCELED = 2;
PAYLOAD_RECEIVED_ACK = 3;
}
optional EventType event = 1;
optional int64 offset = 2;
}
optional PacketType packet_type = 1;
optional PayloadHeader payload_header = 2;
// Exactly one of the following fields will be set, depending on the type.
optional PayloadChunk payload_chunk = 3;
optional ControlMessage control_message = 4;
}
message BandwidthUpgradeNegotiationFrame {
enum EventType {
UNKNOWN_EVENT_TYPE = 0;
UPGRADE_PATH_AVAILABLE = 1;
LAST_WRITE_TO_PRIOR_CHANNEL = 2;
SAFE_TO_CLOSE_PRIOR_CHANNEL = 3;
CLIENT_INTRODUCTION = 4;
UPGRADE_FAILURE = 5;
CLIENT_INTRODUCTION_ACK = 6;
}
// Accompanies UPGRADE_PATH_AVAILABLE and UPGRADE_FAILURE events.
message UpgradePathInfo {
// Should always match cs/symbol:location.nearby.proto.connections.Medium
enum Medium {
UNKNOWN_MEDIUM = 0;
MDNS = 1 [deprecated = true];
BLUETOOTH = 2;
WIFI_HOTSPOT = 3;
BLE = 4;
WIFI_LAN = 5;
WIFI_AWARE = 6;
NFC = 7;
WIFI_DIRECT = 8;
WEB_RTC = 9;
// 10 is reserved.
USB = 11;
}
// Accompanies Medium.WIFI_HOTSPOT.
message WifiHotspotCredentials {
optional string ssid = 1;
optional string password = 2;
optional int32 port = 3;
optional string gateway = 4 [default = "0.0.0.0"];
// This field can be a band or frequency
optional int32 frequency = 5 [default = -1];
}
// Accompanies Medium.WIFI_LAN.
message WifiLanSocket {
optional bytes ip_address = 1;
optional int32 wifi_port = 2;
}
// Accompanies Medium.BLUETOOTH.
message BluetoothCredentials {
optional string service_name = 1;
optional string mac_address = 2;
}
// Accompanies Medium.WIFI_AWARE.
message WifiAwareCredentials {
optional string service_id = 1;
optional bytes service_info = 2;
optional string password = 3;
}
// Accompanies Medium.WIFI_DIRECT.
message WifiDirectCredentials {
optional string ssid = 1;
optional string password = 2;
optional int32 port = 3;
optional int32 frequency = 4;
optional string gateway = 5 [default = "0.0.0.0"];
}
// Accompanies Medium.WEB_RTC
message WebRtcCredentials {
optional string peer_id = 1;
optional LocationHint location_hint = 2;
}
optional Medium medium = 1;
// Exactly one of the following fields will be set.
optional WifiHotspotCredentials wifi_hotspot_credentials = 2;
optional WifiLanSocket wifi_lan_socket = 3;
optional BluetoothCredentials bluetooth_credentials = 4;
optional WifiAwareCredentials wifi_aware_credentials = 5;
optional WifiDirectCredentials wifi_direct_credentials = 6;
optional WebRtcCredentials web_rtc_credentials = 8;
// Disable Encryption for this upgrade medium to improve throughput.
optional bool supports_disabling_encryption = 7;
// An ack will be sent after the CLIENT_INTRODUCTION frame.
optional bool supports_client_introduction_ack = 9;
}
// Accompanies CLIENT_INTRODUCTION events.
message ClientIntroduction {
optional string endpoint_id = 1;
optional bool supports_disabling_encryption = 2;
}
// Accompanies CLIENT_INTRODUCTION_ACK events.
message ClientIntroductionAck {}
optional EventType event_type = 1;
// Exactly one of the following fields will be set.
optional UpgradePathInfo upgrade_path_info = 2;
optional ClientIntroduction client_introduction = 3;
optional ClientIntroductionAck client_introduction_ack = 4;
}
message KeepAliveFrame {
// And ack will be sent after receiving KEEP_ALIVE frame.
optional bool ack = 1;
}
// Informs the remote side to immediately severe the socket connection.
// Used in bandwidth upgrades to get around a race condition, but may be used
// in other situations to trigger a faster disconnection event than waiting for
// socket closed on the remote side.
message DisconnectionFrame {
// Apply safe-to-disconnect protocol if true.
optional bool request_safe_to_disconnect = 1;
// Ack of receiving Disconnection frame will be sent to the sender
// frame.
optional bool ack_safe_to_disconnect = 2;
}
// A paired key encryption packet sent between devices, contains signed data.
message PairedKeyEncryptionFrame {
// The encrypted data (raw authentication token for the established
// connection) in byte array format.
optional bytes signed_data = 1;
}
message MediumMetadata {
// True if local device supports 5GHz.
optional bool supports_5_ghz = 1;
// WiFi LAN BSSID, in the form of a six-byte MAC address: XX:XX:XX:XX:XX:XX
optional string bssid = 2;
// IP address, in network byte order: the highest order byte of the address is
// in byte[0].
optional bytes ip_address = 3;
// True if local device supports 6GHz.
optional bool supports_6_ghz = 4;
// True if local device has mobile radio.
optional bool mobile_radio = 5;
// The frequency of the WiFi LAN AP(in MHz). Or -1 is not associated with an
// AP over WiFi, -2 represents the active network uses an Ethernet transport.
optional int32 ap_frequency = 6 [default = -1];
// Available channels on the local device.
optional AvailableChannels available_channels = 7;
// Usable WiFi Direct client channels on the local device.
optional WifiDirectCliUsableChannels wifi_direct_cli_usable_channels = 8;
// Usable WiFi LAN channels on the local device.
optional WifiLanUsableChannels wifi_lan_usable_channels = 9;
// Usable WiFi Aware channels on the local device.
optional WifiAwareUsableChannels wifi_aware_usable_channels = 10;
// Usable WiFi Hotspot STA channels on the local device.
optional WifiHotspotStaUsableChannels wifi_hotspot_sta_usable_channels = 11;
}
// Available channels on the local device.
message AvailableChannels {
repeated int32 channels = 1 [packed = true];
}
// Usable WiFi Direct client channels on the local device.
message WifiDirectCliUsableChannels {
repeated int32 channels = 1 [packed = true];
}
// Usable WiFi LAN channels on the local device.
message WifiLanUsableChannels {
repeated int32 channels = 1 [packed = true];
}
// Usable WiFi Aware channels on the local device.
message WifiAwareUsableChannels {
repeated int32 channels = 1 [packed = true];
}
// Usable WiFi Hotspot STA channels on the local device.
message WifiHotspotStaUsableChannels {
repeated int32 channels = 1 [packed = true];
}
// LocationHint is used to specify a location as well as format.
message LocationHint {
// Location is the location, provided in the format specified by format.
optional string location = 1;
// the format of location.
optional LocationStandard.Format format = 2;
}
message LocationStandard {
enum Format {
UNKNOWN = 0;
// E164 country codes:
// https://en.wikipedia.org/wiki/List_of_country_calling_codes
// e.g. +1 for USA
E164_CALLING = 1;
// ISO 3166-1 alpha-2 country codes:
// https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
ISO_3166_1_ALPHA_2 = 2;
}
}
// Device capability for OS information.
message OsInfo {
enum OsType {
UNKNOWN_OS_TYPE = 0;
ANDROID = 1;
CHROME_OS = 2;
WINDOWS = 3;
APPLE = 4;
LINUX = 100; // g3 test environment
}
optional OsType type = 1;
}

View File

@@ -0,0 +1,308 @@
// Copyright 2020 Google LLC
//
// 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
//
// https://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.
syntax = "proto2";
package securegcm;
option optimize_for = LITE_RUNTIME;
option java_package = "com.google.security.cryptauth.lib.securegcm";
option java_outer_classname = "SecureGcmProto";
option objc_class_prefix = "SGCM";
// Message used only during enrollment
// Field numbers should be kept in sync with DeviceInfo in:
// java/com/google/security/cryptauth/backend/services/common/common.proto
message GcmDeviceInfo {
// This field's name does not match the one in DeviceInfo for legacy reasons.
// Consider using long_device_id and device_type instead when enrolling
// non-android devices.
optional fixed64 android_device_id = 1;
// Used for device_address of DeviceInfo field 2, but for GCM capable devices.
optional bytes gcm_registration_id = 102;
// Used for device_address of DeviceInfo field 2, but for iOS devices.
optional bytes apn_registration_id = 202;
// Does the user have notifications enabled for the given device address.
optional bool notification_enabled = 203 [default = true];
// Used for device_address of DeviceInfo field 2, a Bluetooth Mac address for
// the device (e.g., to be used with EasyUnlock)
optional string bluetooth_mac_address = 302;
// SHA-256 hash of the device master key (from the key exchange).
// Differs from DeviceInfo field 3, which contains the actual master key.
optional bytes device_master_key_hash = 103;
// A SecureMessage.EcP256PublicKey
required bytes user_public_key = 4;
// device's model name
// (e.g., an android.os.Build.MODEL or UIDevice.model)
optional string device_model = 7;
// device's locale
optional string locale = 8;
// The handle for user_public_key (and implicitly, a master key)
optional bytes key_handle = 9;
// The initial counter value for the device, sent by the device
optional int64 counter = 12 [default = 0];
// The Operating System version on the device
// (e.g., an android.os.Build.DISPLAY or UIDevice.systemVersion)
optional string device_os_version = 13;
// The Operating System version number on the device
// (e.g., an android.os.Build.VERSION.SDK_INT)
optional int64 device_os_version_code = 14;
// The Operating System release on the device
// (e.g., an android.os.Build.VERSION.RELEASE)
optional string device_os_release = 15;
// The Operating System codename on the device
// (e.g., an android.os.Build.VERSION.CODENAME or UIDevice.systemName)
optional string device_os_codename = 16;
// The software version running on the device
// (e.g., Authenticator app version string)
optional string device_software_version = 17;
// The software version number running on the device
// (e.g., Authenticator app version code)
optional int64 device_software_version_code = 18;
// Software package information if applicable
// (e.g., com.google.android.apps.authenticator2)
optional string device_software_package = 19;
// Size of the display in thousandths of an inch (e.g., 7000 mils = 7 in)
optional int32 device_display_diagonal_mils = 22;
// For Authzen capable devices, their Authzen protocol version
optional int32 device_authzen_version = 24;
// Not all devices have device identifiers that fit in 64 bits.
optional bytes long_device_id = 29;
// The device manufacturer name
// (e.g., android.os.Build.MANUFACTURER)
optional string device_manufacturer = 31;
// Used to indicate which type of device this is.
optional DeviceType device_type = 32 [default = ANDROID];
// Fields corresponding to screenlock type/features and hardware features
// should be numbered in the 400 range.
// Is this device using a secure screenlock (e.g., pattern or pin unlock)
optional bool using_secure_screenlock = 400 [default = false];
// Is auto-unlocking the screenlock (e.g., when at "home") supported?
optional bool auto_unlock_screenlock_supported = 401 [default = false];
// Is auto-unlocking the screenlock (e.g., when at "home") enabled?
optional bool auto_unlock_screenlock_enabled = 402 [default = false];
// Does the device have a Bluetooth (classic) radio?
optional bool bluetooth_radio_supported = 403 [default = false];
// Is the Bluetooth (classic) radio on?
optional bool bluetooth_radio_enabled = 404 [default = false];
// Does the device hardware support a mobile data connection?
optional bool mobile_data_supported = 405 [default = false];
// Does the device support tethering?
optional bool tethering_supported = 406 [default = false];
// Does the device have a BLE radio?
optional bool ble_radio_supported = 407 [default = false];
// Is the device a "Pixel Experience" Android device?
optional bool pixel_experience = 408 [default = false];
// Is the device running in the ARC++ container on a chromebook?
optional bool arc_plus_plus = 409 [default = false];
// Is the value set in |using_secure_screenlock| reliable? On some Android
// devices, the platform API to get the screenlock state is not trustworthy.
// See b/32212161.
optional bool is_screenlock_state_flaky = 410 [default = false];
// A list of multi-device software features supported by the device.
repeated SoftwareFeature supported_software_features = 411;
// A list of multi-device software features currently enabled (active) on the
// device.
repeated SoftwareFeature enabled_software_features = 412;
// The enrollment session id this is sent with
optional bytes enrollment_session_id = 1000;
// A copy of the user's OAuth token
optional string oauth_token = 1001;
}
// This enum is used by iOS devices as values for device_display_diagonal_mils
// in GcmDeviceInfo. There is no good way to calculate it on those devices.
enum AppleDeviceDiagonalMils {
// This is the mils diagonal on an iPhone 5.
APPLE_PHONE = 4000;
// This is the mils diagonal on an iPad mini.
APPLE_PAD = 7900;
}
// This should be kept in sync with DeviceType in:
// java/com/google/security/cryptauth/backend/services/common/common_enums.proto
enum DeviceType {
UNKNOWN = 0;
ANDROID = 1;
CHROME = 2;
IOS = 3;
BROWSER = 4;
OSX = 5;
}
// MultiDevice features which may be supported and enabled on a device. See
enum SoftwareFeature {
UNKNOWN_FEATURE = 0;
BETTER_TOGETHER_HOST = 1;
BETTER_TOGETHER_CLIENT = 2;
EASY_UNLOCK_HOST = 3;
EASY_UNLOCK_CLIENT = 4;
MAGIC_TETHER_HOST = 5;
MAGIC_TETHER_CLIENT = 6;
SMS_CONNECT_HOST = 7;
SMS_CONNECT_CLIENT = 8;
}
// A list of "reasons" that can be provided for calling server-side APIs.
// This is particularly important for calls that can be triggered by different
// kinds of events. Please try to keep reasons as generic as possible, so that
// codes can be re-used by various callers in a sensible fashion.
enum InvocationReason {
REASON_UNKNOWN = 0;
// First run of the software package invoking this call
REASON_INITIALIZATION = 1;
// Ordinary periodic actions (e.g. monthly master key rotation)
REASON_PERIODIC = 2;
// Slow-cycle periodic action (e.g. yearly keypair rotation???)
REASON_SLOW_PERIODIC = 3;
// Fast-cycle periodic action (e.g. daily sync for Smart Lock users)
REASON_FAST_PERIODIC = 4;
// Expired state (e.g. expired credentials, or cached entries) was detected
REASON_EXPIRATION = 5;
// An unexpected protocol failure occurred (so attempting to repair state)
REASON_FAILURE_RECOVERY = 6;
// A new account has been added to the device
REASON_NEW_ACCOUNT = 7;
// An existing account on the device has been changed
REASON_CHANGED_ACCOUNT = 8;
// The user toggled the state of a feature (e.g. Smart Lock enabled via BT)
REASON_FEATURE_TOGGLED = 9;
// A "push" from the server caused this action (e.g. a sync tickle)
REASON_SERVER_INITIATED = 10;
// A local address change triggered this (e.g. GCM registration id changed)
REASON_ADDRESS_CHANGE = 11;
// A software update has triggered this
REASON_SOFTWARE_UPDATE = 12;
// A manual action by the user triggered this (e.g. commands sent via adb)
REASON_MANUAL = 13;
// A custom key has been invalidated on the device (e.g. screen lock is
// disabled).
REASON_CUSTOM_KEY_INVALIDATION = 14;
// Periodic action triggered by auth_proximity
REASON_PROXIMITY_PERIODIC = 15;
}
enum Type {
ENROLLMENT = 0;
TICKLE = 1;
TX_REQUEST = 2;
TX_REPLY = 3;
TX_SYNC_REQUEST = 4;
TX_SYNC_RESPONSE = 5;
TX_PING = 6;
DEVICE_INFO_UPDATE = 7;
TX_CANCEL_REQUEST = 8;
// DEPRECATED (can be re-used after Aug 2015)
PROXIMITYAUTH_PAIRING = 10;
// The kind of identity assertion generated by a "GCM V1" device (i.e.,
// an Android phone that has registered with us a public and a symmetric
// key)
GCMV1_IDENTITY_ASSERTION = 11;
// Device-to-device communications are protected by an unauthenticated
// Diffie-Hellman exchange. The InitiatorHello message is simply the
// initiator's public DH key, and is not encoded as a SecureMessage, so
// it doesn't have a tag.
// The ResponderHello message (which is sent by the responder
// to the initiator), on the other hand, carries a payload that is protected
// by the derived shared key. It also contains the responder's
// public DH key. ResponderHelloAndPayload messages have the
// DEVICE_TO_DEVICE_RESPONDER_HELLO tag.
DEVICE_TO_DEVICE_RESPONDER_HELLO_PAYLOAD = 12;
// Device-to-device communications are protected by an unauthenticated
// Diffie-Hellman exchange. Once the initiator and responder
// agree on a shared key (through Diffie-Hellman), they will use messages
// tagged with DEVICE_TO_DEVICE_MESSAGE to exchange data.
DEVICE_TO_DEVICE_MESSAGE = 13;
// Notification to let a device know it should contact a nearby device.
DEVICE_PROXIMITY_CALLBACK = 14;
// Device-to-device communications are protected by an unauthenticated
// Diffie-Hellman exchange. During device-to-device authentication, the first
// message from initiator (the challenge) is signed and put into the payload
// of the message sent back to the initiator.
UNLOCK_KEY_SIGNED_CHALLENGE = 15;
// Specialty (corp only) features
LOGIN_NOTIFICATION = 101;
}
message GcmMetadata {
required Type type = 1;
optional int32 version = 2 [default = 0];
}
message Tickle {
// Time after which this tickle should expire
optional fixed64 expiry_time = 1;
}
message LoginNotificationInfo {
// Time at which the server received the login notification request.
optional fixed64 creation_time = 2;
// Must correspond to user_id in LoginNotificationRequest, if set.
optional string email = 3;
// Host where the user's credentials were used to login, if meaningful.
optional string host = 4;
// Location from where the user's credentials were used, if meaningful.
optional string source = 5;
// Type of login, e.g. ssh, gnome-screensaver, or web.
optional string event_type = 6;
}

View File

@@ -0,0 +1,126 @@
// Copyright 2020 Google LLC
//
// 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
//
// https://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.
// Proto definitions for SecureMessage format
syntax = "proto2";
package securemessage;
option optimize_for = LITE_RUNTIME;
option java_package = "com.google.security.cryptauth.lib.securemessage";
option java_outer_classname = "SecureMessageProto";
option objc_class_prefix = "SMSG";
message SecureMessage {
// Must contain a HeaderAndBody message
required bytes header_and_body = 1;
// Signature of header_and_body
required bytes signature = 2;
}
// Supported "signature" schemes (both symmetric key and public key based)
enum SigScheme {
HMAC_SHA256 = 1;
ECDSA_P256_SHA256 = 2;
// Not recommended -- use ECDSA_P256_SHA256 instead
RSA2048_SHA256 = 3;
}
// Supported encryption schemes
enum EncScheme {
// No encryption
NONE = 1;
AES_256_CBC = 2;
}
message Header {
required SigScheme signature_scheme = 1;
required EncScheme encryption_scheme = 2;
// Identifies the verification key
optional bytes verification_key_id = 3;
// Identifies the decryption key
optional bytes decryption_key_id = 4;
// Encryption may use an IV
optional bytes iv = 5;
// Arbitrary per-protocol public data, to be sent with the plain-text header
optional bytes public_metadata = 6;
// The length of some associated data this is not sent in this SecureMessage,
// but which will be bound to the signature.
optional uint32 associated_data_length = 7 [default = 0];
}
message HeaderAndBody {
// Public data about this message (to be bound in the signature)
required Header header = 1;
// Payload data
required bytes body = 2;
}
// Must be kept wire-format compatible with HeaderAndBody. Provides the
// SecureMessage code with a consistent wire-format representation that
// remains stable irrespective of protobuf implementation choices. This
// low-level representation of a HeaderAndBody should not be used by
// any code outside of the SecureMessage library implementation/tests.
message HeaderAndBodyInternal {
// A raw (wire-format) byte encoding of a Header, suitable for hashing
required bytes header = 1;
// Payload data
required bytes body = 2;
}
// -------
// The remainder of the messages defined here are provided only for
// convenience. They are not needed for SecureMessage proper, but are
// commonly useful wherever SecureMessage might be applied.
// -------
// A list of supported public key types
enum PublicKeyType {
EC_P256 = 1;
RSA2048 = 2;
// 2048-bit MODP group 14, from RFC 3526
DH2048_MODP = 3;
}
// A convenience proto for encoding NIST P-256 elliptic curve public keys
message EcP256PublicKey {
// x and y are encoded in big-endian two's complement (slightly wasteful)
// Client MUST verify (x,y) is a valid point on NIST P256
required bytes x = 1;
required bytes y = 2;
}
// A convenience proto for encoding RSA public keys with small exponents
message SimpleRsaPublicKey {
// Encoded in big-endian two's complement
required bytes n = 1;
optional int32 e = 2 [default = 65537];
}
// A convenience proto for encoding Diffie-Hellman public keys,
// for use only when Elliptic Curve based key exchanges are not possible.
// (Note that the group parameters must be specified separately)
message DhPublicKey {
// Big-endian two's complement encoded group element
required bytes y = 1;
}
message GenericPublicKey {
required PublicKeyType type = 1;
optional EcP256PublicKey ec_p256_public_key = 2;
optional SimpleRsaPublicKey rsa2048_public_key = 3;
// Use only as a last resort
optional DhPublicKey dh2048_public_key = 4;
}

View File

@@ -0,0 +1,105 @@
// Copyright 2020 Google LLC
//
// 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
//
// https://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.
syntax = "proto2";
package securegcm;
option optimize_for = LITE_RUNTIME;
option java_package = "com.google.security.cryptauth.lib.securegcm";
option java_outer_classname = "UkeyProto";
message Ukey2Message {
enum Type {
UNKNOWN_DO_NOT_USE = 0;
ALERT = 1;
CLIENT_INIT = 2;
SERVER_INIT = 3;
CLIENT_FINISH = 4;
}
optional Type message_type = 1; // Identifies message type
optional bytes message_data = 2; // Actual message, to be parsed according to
// message_type
}
message Ukey2Alert {
enum AlertType {
// Framing errors
BAD_MESSAGE = 1; // The message could not be deserialized
BAD_MESSAGE_TYPE = 2; // message_type has an undefined value
INCORRECT_MESSAGE = 3; // message_type received does not correspond to
// expected type at this stage of the protocol
BAD_MESSAGE_DATA = 4; // Could not deserialize message_data as per
// value inmessage_type
// ClientInit and ServerInit errors
BAD_VERSION = 100; // version is invalid; server cannot find
// suitable version to speak with client.
BAD_RANDOM = 101; // Random data is missing or of incorrect
// length
BAD_HANDSHAKE_CIPHER = 102; // No suitable handshake ciphers were found
BAD_NEXT_PROTOCOL = 103; // The next protocol is missing, unknown, or
// unsupported
BAD_PUBLIC_KEY = 104; // The public key could not be parsed
// Other errors
INTERNAL_ERROR = 200; // An internal error has occurred. error_message
// may contain additional details for logging
// and debugging.
}
optional AlertType type = 1;
optional string error_message = 2;
}
enum Ukey2HandshakeCipher {
RESERVED = 0;
P256_SHA512 = 100; // NIST P-256 used for ECDH, SHA512 used for
// commitment
CURVE25519_SHA512 = 200; // Curve 25519 used for ECDH, SHA512 used for
// commitment
}
message Ukey2ClientInit {
optional int32 version = 1; // highest supported version for rollback
// protection
optional bytes random = 2; // random bytes for replay/reuse protection
// One commitment (hash of ClientFinished containing public key) per supported
// cipher
message CipherCommitment {
optional Ukey2HandshakeCipher handshake_cipher = 1;
optional bytes commitment = 2;
}
repeated CipherCommitment cipher_commitments = 3;
// Next protocol that the client wants to speak.
optional string next_protocol = 4;
}
message Ukey2ServerInit {
optional int32 version = 1; // highest supported version for rollback
// protection
optional bytes random = 2; // random bytes for replay/reuse protection
// Selected Cipher and corresponding public key
optional Ukey2HandshakeCipher handshake_cipher = 3;
optional bytes public_key = 4;
}
message Ukey2ClientFinished {
optional bytes public_key = 1; // public key matching selected handshake
// cipher
}

View File

@@ -0,0 +1,236 @@
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Brought from: //depot/google3/location/nearby/sharing/proto/wire_format.proto
// At CL 317565061
syntax = "proto2";
package sharing.nearby;
// Required in Chrome.
option optimize_for = LITE_RUNTIME;
// File metadata. Does not include the actual bytes of the file.
// NEXT_ID=6
message FileMetadata {
enum Type {
UNKNOWN = 0;
IMAGE = 1;
VIDEO = 2;
APP = 3;
AUDIO = 4;
}
// The human readable name of this file (eg. 'Cookbook.pdf').
optional string name = 1;
// The type of file (eg. 'IMAGE' from 'dog.jpg'). Specifying a type helps
// provide a richer experience on the receiving side.
optional Type type = 2 [default = UNKNOWN];
// The FILE payload id that will be sent as a follow up containing the actual
// bytes of the file.
optional int64 payload_id = 3;
// The total size of the file.
optional int64 size = 4;
// The mimeType of file (eg. 'image/jpeg' from 'dog.jpg'). Specifying a
// mimeType helps provide a richer experience on receiving side.
optional string mime_type = 5 [default = "application/octet-stream"];
// A uuid for the attachment. Should be unique across all attachments.
optional int64 id = 6;
}
// NEXT_ID=5
message TextMetadata {
enum Type {
UNKNOWN = 0;
TEXT = 1;
// Open with browsers.
URL = 2;
// Open with map apps.
ADDRESS = 3;
// Dial.
PHONE_NUMBER = 4;
}
// The title of the text content.
optional string text_title = 2;
// The type of text (phone number, url, address, or plain text).
optional Type type = 3 [default = UNKNOWN];
// The BYTE payload id that will be sent as a follow up containing the actual
// bytes of the text.
optional int64 payload_id = 4;
// The size of the text content.
optional int64 size = 5;
// A uuid for the attachment. Should be unique across all attachments.
optional int64 id = 6;
}
// NEXT_ID=5
message WifiCredentialsMetadata {
enum SecurityType {
UNKNOWN_SECURITY_TYPE = 0;
OPEN = 1;
WPA_PSK = 2;
WEP = 3;
}
// The Wifi network name. This will be sent in introduction.
optional string ssid = 2;
// The security type of network (OPEN, WPA_PSK, WEP).
optional SecurityType security_type = 3 [default = UNKNOWN_SECURITY_TYPE];
// The BYTE payload id that will be sent as a follow up containing the
// password.
optional int64 payload_id = 4;
// A uuid for the attachment. Should be unique across all attachments.
optional int64 id = 5;
}
// A frame used when sending messages over the wire.
// NEXT_ID=3
message Frame {
enum Version {
UNKNOWN_VERSION = 0;
V1 = 1;
}
optional Version version = 1;
// Right now there's only 1 version, but if there are more, exactly one of
// the following fields will be set.
optional V1Frame v1 = 2;
}
// NEXT_ID=7
message V1Frame {
enum FrameType {
UNKNOWN_FRAME_TYPE = 0;
INTRODUCTION = 1;
RESPONSE = 2;
PAIRED_KEY_ENCRYPTION = 3;
PAIRED_KEY_RESULT = 4;
CERTIFICATE_INFO = 5;
CANCEL = 6;
}
optional FrameType type = 1;
// Exactly one of the following fields will be set.
optional IntroductionFrame introduction = 2;
optional ConnectionResponseFrame connection_response = 3;
optional PairedKeyEncryptionFrame paired_key_encryption = 4;
optional PairedKeyResultFrame paired_key_result = 5;
optional CertificateInfoFrame certificate_info = 6;
}
// An introduction packet sent by the sending side. Contains a list of files
// they'd like to share.
// NEXT_ID=4
message IntroductionFrame {
repeated FileMetadata file_metadata = 1;
repeated TextMetadata text_metadata = 2;
// The required app package to open the content. May be null.
optional string required_package = 3;
repeated WifiCredentialsMetadata wifi_credentials_metadata = 4;
}
// A response packet sent by the receiving side. Accepts or rejects the list of
// files.
// NEXT_ID=2
message ConnectionResponseFrame {
enum Status {
UNKNOWN = 0;
ACCEPT = 1;
REJECT = 2;
NOT_ENOUGH_SPACE = 3;
UNSUPPORTED_ATTACHMENT_TYPE = 4;
TIMED_OUT = 5;
}
// The receiving side's response.
optional Status status = 1;
}
// A paired key encryption packet sent between devices, contains signed data.
// NEXT_ID=3
message PairedKeyEncryptionFrame {
// The encrypted data in byte array format.
optional bytes signed_data = 1;
// The hash of a certificate id.
optional bytes secret_id_hash = 2;
// An optional encrypted data in byte array format.
optional bytes optional_signed_data = 3;
}
// A paired key verification result packet sent between devices.
// NEXT_ID=2
message PairedKeyResultFrame {
enum Status {
UNKNOWN = 0;
SUCCESS = 1;
FAIL = 2;
UNABLE = 3;
}
// The verification result.
optional Status status = 1;
}
// A package containing certificate info to be shared to remote device offline.
// NEXT_ID=2
message CertificateInfoFrame {
// The public certificates to be shared with remote devices.
repeated PublicCertificate public_certificate = 1;
}
// A public certificate from the local device.
// NEXT_ID=8
message PublicCertificate {
// The unique id of the public certificate.
optional bytes secret_id = 1;
// A bytes representation of a Secret Key owned by contact, to decrypt the
// metadata_key stored within the advertisement.
optional bytes authenticity_key = 2;
// A bytes representation a public key of X509Certificate, owned by contact,
// to decrypt encrypted UKEY2 (from Nearby Connections API) as a hand shake in
// contact verification phase.
optional bytes public_key = 3;
// The time in millis from epoch when this certificate becomes effective.
optional int64 start_time = 4;
// The time in millis from epoch when this certificate expires.
optional int64 end_time = 5;
// The encrypted metadata in bytes, contains personal information of the
// device/user who created this certificate. Needs to be decrypted into bytes,
// and converted back to EncryptedMetadata object to access fields.
optional bytes encrypted_metadata_bytes = 6;
// The tag for verifying metadata_encryption_key.
optional bytes metadata_encryption_key_tag = 7;
}
// NEXT_ID=3
message WifiCredentials {
// Wi-Fi password.
optional string password = 1;
// True if the network is a hidden network that is not broadcasting its SSID.
// Default is false.
optional bool hidden_ssid = 2 [default = false];
}