Skip to content

Commit

Permalink
Merge branch 'swift4'
Browse files Browse the repository at this point in the history
# Conflicts:
#	Tests/SRPTests/TestUtils.swift
  • Loading branch information
Bouke committed Sep 16, 2017
2 parents 99019ff + b6c1124 commit 3e9ee4d
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 71 deletions.
2 changes: 1 addition & 1 deletion .swift-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.1.1
4.0-DEVELOPMENT-SNAPSHOT-2017-09-13-a
18 changes: 14 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
os:
- osx
- linux
env:
- INTEGRATION_TESTS=false
- INTEGRATION_TESTS=true
language: generic
sudo: required
dist: trusty
osx_image: xcode8.2
osx_image: xcode9
before_install:
- python -V
- pip -V
install:
- pip install srptools
- if [ $INTEGRATION_TESTS == 'true' ]; then pip install srptools; fi
- eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)"
script: make test
script:
- if [ $INTEGRATION_TESTS == 'true' ]; then make test-with-python; fi
- if [ $INTEGRATION_TESTS == 'false' ]; then make test; fi
matrix:
allow_failures:
- env: INTEGRATION_TESTS=true
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
test:
swift test -c release -Xswiftc -enable-testing
test-with-python:
PYTHON=`which python` swift test -c release -Xswiftc -enable-testing
debug-test:
PYTHON=`which python` swift test -c release -Xswiftc -enable-testing -Xswiftc -D -Xswiftc DEBUG
13 changes: 10 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
// swift-tools-version:4.0

import PackageDescription

let package = Package(
name: "SRP",
dependencies: [
.Package(url: "https://github.com/IBM-Swift/BlueCryptor.git", majorVersion: 0, minor: 8),
.Package(url: "https://github.com/lorentey/BigInt.git", majorVersion: 2, minor: 1),
]
.package(url: "https://github.com/IBM-Swift/BlueCryptor.git", from: "0.8.16"),
.package(url: "https://github.com/lorentey/BigInt.git", from: "3.0.0"),
],
targets: [
.target(name: "SRP", dependencies: ["Cryptor", "BigInt"], path: "Sources"),
.testTarget(name: "SRPTests", dependencies: ["Cryptor", "SRP"]),
],
swiftLanguageVersions: [4]
)
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ assert(server.sessionKey == client.sessionKey)

More information can be found in the [documentation](http://boukehaarsma.nl/SRP).

## Swift Compatibility

Swift 4 is required with version 3 of this package. Use version 2 if you need
Swift 3 compatibility.

## Compatibility with other implementations

I like to believe this implementation does correctly implements the RFC.
Expand Down
72 changes: 15 additions & 57 deletions Tests/SRPTests/TestUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ let remotepy = URL(fileURLWithPath: #file)
.deletingLastPathComponent()
.appendingPathComponent("remote.py")

enum RemoteError: Error {
indirect enum RemoteError: Error {
case noPython
case unexpectedPrompt(String)
case commandFailure
case commandFailureWithMessage(String)
case valueExpected
case valueExpected(RemoteError)
case unexpectedValueLabel(String)
case decodingError
case unexpectedExit
case unexpectedExit(RemoteError)
}

class Remote {
Expand All @@ -53,10 +53,6 @@ class Remote {
var fileHandleForReading: FileHandle {
return pipe.fileHandleForReading
}

var fileHandleForWriting: FileHandle {
return pipe.fileHandleForWriting
}
}

fileprivate init(process: Process) {
Expand All @@ -71,9 +67,6 @@ class Remote {


fileprivate func write(prompt expectedPrompt: String, line: String) throws {
#if DEBUG
print("DEBUG: Expecting prompt '\(expectedPrompt)'")
#endif
let prompt = try readprompt(from: output)
guard prompt == "\(expectedPrompt): " else {
throw RemoteError.unexpectedPrompt(prompt)
Expand All @@ -83,46 +76,26 @@ class Remote {

private func writeline(_ line: String) {
input.fileHandleForWriting.write("\(line)\n".data(using: .ascii)!)

#if DEBUG
print("DEBUG: > \(line)")
#endif
}

private func readprompt(from pipe: BufferedPipe) throws -> String {
if !process.isRunning {
throw RemoteError.unexpectedExit
throw RemoteError.unexpectedExit(readError())
}
if pipe.buffer.count > 0 {
defer { pipe.buffer = Data() }
return String(data: pipe.buffer, encoding: .ascii)!
} else {
let availableData = pipe.fileHandleForReading.availableData
guard let prompt = String(data: availableData, encoding: .ascii) else {
throw RemoteError.decodingError
}
#if DEBUG
print("DEBUG: < \(prompt)")
#endif
return prompt
return String(data: pipe.fileHandleForReading.availableData, encoding: .ascii)!
}
}

fileprivate func read(label: String, from pipe: BufferedPipe) throws -> (String) {
#if DEBUG
print("DEBUG: Expecting label '\(label)'")
#endif
let splitted = try readline(from: pipe).components(separatedBy: ": ")
guard splitted.count == 2 else {
#if DEBUG
print("ERROR: \(readError())")
#endif
throw RemoteError.valueExpected
throw RemoteError.valueExpected(readError())
}
guard label == splitted[0] else {
#if DEBUG
print("ERROR: \(readError())")
#endif
throw RemoteError.unexpectedValueLabel(splitted[0])
}
return splitted[1]
Expand All @@ -132,35 +105,20 @@ class Remote {
while true {
if let eol = pipe.buffer.index(of: 10) {
defer {
// Slicing of Data is broken on Linux... workaround by creating new Data.
pipe.buffer = Data(pipe.buffer.dropFirst(eol - pipe.buffer.startIndex + 1))
let lineLength = eol - pipe.buffer.startIndex + 1
pipe.buffer.removeFirst(lineLength)
}
guard let line = String(data: Data(pipe.buffer[pipe.buffer.startIndex..<eol]), encoding: .utf8) else {
throw RemoteError.decodingError
}
return line
} else if pipe.buffer.count > 0 {
#if DEBUG
print("DEBUG: Available buffer, but without a newline")
#endif
}

let availableData = pipe.fileHandleForReading.availableData
pipe.buffer.append(availableData)

#if DEBUG
if let availableOutput = String(data: availableData, encoding: .utf8) {
for line in availableOutput.characters.split(separator: "\n") {
print("DEBUG: < \(String(line))")
}
} else {
print("DEBUG: Could not decode output")
}
#endif

if availableData.count == 0 && !process.isRunning {
// No more data coming and buffer doesn't contain a newline
throw RemoteError.unexpectedExit
throw RemoteError.unexpectedExit(readError())
}
}
}
Expand Down Expand Up @@ -227,7 +185,7 @@ class RemoteServer: Remote {
}
super.init(process: process)

verificationKey = try Data(hex: read(label: "v", from: error))
verificationKey = try Data(hex: read(label: "v", from: output))
}

/// Get server's challenge
Expand All @@ -238,7 +196,7 @@ class RemoteServer: Remote {
func getChallenge(publicKey A: Data) throws -> (salt: Data, publicKey: Data) {
do {
try write(prompt: "A", line: A.hex)
privateKey = try Data(hex: try read(label: "b", from: error))
privateKey = try Data(hex: try read(label: "b", from: output))
salt = try Data(hex: try read(label: "s", from: output))
publicKey = try Data(hex: try read(label: "B", from: output))
return (salt!, publicKey!)
Expand All @@ -255,7 +213,7 @@ class RemoteServer: Remote {
func verifySession(keyProof M: Data) throws -> Data {
do {
try write(prompt: "M", line: M.hex)
expectedM = try Data(hex: try read(label: "expected M", from: error))
expectedM = try Data(hex: try read(label: "expected M", from: output))
return try Data(hex: try read(label: "HAMK", from: output))
} catch RemoteError.unexpectedExit {
throw readError()
Expand All @@ -267,7 +225,7 @@ class RemoteServer: Remote {
/// - Returns: session key
/// - Throws: on I/O Error
func getSessionKey() throws -> Data {
return try Data(hex: try read(label: "K", from: error))
return try Data(hex: try read(label: "K", from: output))
}
}

Expand Down Expand Up @@ -312,7 +270,7 @@ class RemoteClient: Remote {
}
super.init(process: process)

self.privateKey = try Data(hex: try read(label: "a", from: error))
self.privateKey = try Data(hex: try read(label: "a", from: output))
}

/// Read public key from stdout.
Expand Down Expand Up @@ -353,6 +311,6 @@ class RemoteClient: Remote {
/// - Returns: session key (K)
/// - Throws: on I/O Error
func getSessionKey() throws -> Data {
return try Data(hex: try read(label: "K", from: error))
return try Data(hex: try read(label: "K", from: output))
}
}
12 changes: 6 additions & 6 deletions remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def hex_encoded_utf8(value):
else:
_, password_verifier, salt = context.get_user_data_triplet()

print("v:", password_verifier, file=sys.stderr)
print("v:", password_verifier)

# Client => Server: username, A
sys.stdout.write("A: ")
Expand All @@ -119,7 +119,7 @@ def hex_encoded_utf8(value):
# Receive username from client and generate server public.
server_session = SRPServerSession(context, password_verifier, private=args.private)

print("b:", server_session.private, file=sys.stderr)
print("b:", server_session.private)

# Server => Client: s, B
print("s:", salt)
Expand All @@ -132,19 +132,19 @@ def hex_encoded_utf8(value):

# Process client public and verify session key proof.
server_session.process(A, salt)
print("expected M:", server_session.key_proof, file=sys.stderr)
print("expected M:", server_session.key_proof)

assert server_session.verify_proof(M)

# Server => Client: HAMK
print("HAMK:", ensure_hash_size(server_session.key_proof_hash))

# Always keep the key secret! It is printed to validate the implementation.
print("K:", ensure_hash_size(server_session.key), file=sys.stderr)
print("K:", ensure_hash_size(server_session.key))

if args.command == "client":
client_session = SRPClientSession(context, private=args.private)
print("a:", client_session.private, file=sys.stderr)
print("a:", client_session.private)

# Client => Server: username, A
print("A:", client_session.public)
Expand All @@ -169,4 +169,4 @@ def hex_encoded_utf8(value):
print("OK")

# Always keep the key secret! It is printed to validate the implementation.
print("K:", ensure_hash_size(client_session.key), file=sys.stderr)
print("K:", ensure_hash_size(client_session.key))

0 comments on commit 3e9ee4d

Please sign in to comment.