diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index d2e589e853b23e615754231cb7bdb541ed250567..0c7fc7754c1fa5899fcf8714bd68db0d204b279f 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -1092,7 +1092,7 @@ TargetAttributes = { A13526741D955BDF00D3BFE1 = { CreatedOnToolsVersion = 7.3.1; - DevelopmentTeam = 4377G946WP; + DevelopmentTeam = VJ9C93G68Y; LastSwiftMigration = 0820; ProvisioningStyle = Automatic; SystemCapabilities = { @@ -1706,7 +1706,7 @@ CODE_SIGN_ENTITLEMENTS = enzevalos_iphone/enzevalos_iphone.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DEVELOPMENT_TEAM = 4377G946WP; + DEVELOPMENT_TEAM = VJ9C93G68Y; INFOPLIST_FILE = enzevalos_iphone/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -1735,7 +1735,7 @@ "-framework", "\"VENTokenField\"", ); - PRODUCT_BUNDLE_IDENTIFIER = "fu-berlin.enzevalos"; + PRODUCT_BUNDLE_IDENTIFIER = "fu-berlin.enzevalos-iphone"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1756,7 +1756,7 @@ CODE_SIGN_ENTITLEMENTS = enzevalos_iphone/enzevalos_iphone.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DEVELOPMENT_TEAM = 4377G946WP; + DEVELOPMENT_TEAM = VJ9C93G68Y; INFOPLIST_FILE = enzevalos_iphone/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -1785,7 +1785,7 @@ "-framework", "\"VENTokenField\"", ); - PRODUCT_BUNDLE_IDENTIFIER = "fu-berlin.enzevalos"; + PRODUCT_BUNDLE_IDENTIFIER = "fu-berlin.enzevalos-iphone"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/Contents.json b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/Contents.json index 19882d568afa3dc606f10cc14b661c17c824d11c..51746c42c744efeda77a3e6109460af9719f9e30 100644 --- a/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,48 +1,57 @@ { "images" : [ { - "idiom" : "iphone", "size" : "20x20", + "idiom" : "iphone", + "filename" : "letterbox40.png", "scale" : "2x" }, { - "idiom" : "iphone", "size" : "20x20", + "idiom" : "iphone", + "filename" : "letterbox60.png", "scale" : "3x" }, { - "idiom" : "iphone", "size" : "29x29", + "idiom" : "iphone", + "filename" : "letterbox58.png", "scale" : "2x" }, { - "idiom" : "iphone", "size" : "29x29", + "idiom" : "iphone", + "filename" : "letterbox87.png", "scale" : "3x" }, { - "idiom" : "iphone", "size" : "40x40", + "idiom" : "iphone", + "filename" : "letterbox80.png", "scale" : "2x" }, { - "idiom" : "iphone", "size" : "40x40", + "idiom" : "iphone", + "filename" : "letterbox120-1.png", "scale" : "3x" }, { - "idiom" : "iphone", "size" : "60x60", + "idiom" : "iphone", + "filename" : "letterbox120.png", "scale" : "2x" }, { - "idiom" : "iphone", "size" : "60x60", + "idiom" : "iphone", + "filename" : "letterbox180.png", "scale" : "3x" }, { - "idiom" : "ios-marketing", "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "letterbox1024.png", "scale" : "1x" } ], diff --git a/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox1024.png b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox1024.png new file mode 100644 index 0000000000000000000000000000000000000000..1546b231a6cfe061e6894279249002536871b5db Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox1024.png differ diff --git a/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox120-1.png b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox120-1.png new file mode 100644 index 0000000000000000000000000000000000000000..3effd04e75926292ef575db781606a60d8db8cdd Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox120-1.png differ diff --git a/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox120.png b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox120.png new file mode 100644 index 0000000000000000000000000000000000000000..3effd04e75926292ef575db781606a60d8db8cdd Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox120.png differ diff --git a/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox180.png b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox180.png new file mode 100644 index 0000000000000000000000000000000000000000..9b0a99be58b2a8f7571504d3fe9de7c4b485c816 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox180.png differ diff --git a/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox40.png b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox40.png new file mode 100644 index 0000000000000000000000000000000000000000..cf01404ab111db00cfa6064f135285f5f64575b3 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox40.png differ diff --git a/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox58.png b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox58.png new file mode 100644 index 0000000000000000000000000000000000000000..136f43c6b7de659a5c6df3e796d86ed0e1400269 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox58.png differ diff --git a/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox60.png b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox60.png new file mode 100644 index 0000000000000000000000000000000000000000..3aea33b77b0bfb63fdd22971283a573a827eb605 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox60.png differ diff --git a/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox80.png b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox80.png new file mode 100644 index 0000000000000000000000000000000000000000..026025ad06f822621f29e88d791aaf5542348548 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox80.png differ diff --git a/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox87.png b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox87.png new file mode 100644 index 0000000000000000000000000000000000000000..b8f0e1ea63418c887b724be6e0e82e9291cb2312 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/AppIcon.appiconset/letterbox87.png differ diff --git a/enzevalos_iphone/CryptoObject.swift b/enzevalos_iphone/CryptoObject.swift index ddeb212fd0115b39798f29f0bb10947bddd997dc..86825b50cd7f4d3b4b76fb01c34ef282d08c9805 100644 --- a/enzevalos_iphone/CryptoObject.swift +++ b/enzevalos_iphone/CryptoObject.swift @@ -33,6 +33,7 @@ public class CryptoObject{ let encryptionState: EncryptionState let signKey: String? let encType: CryptoScheme + let passcode: String? var decryptedText: String?{ if let data = decryptedData{ @@ -50,6 +51,7 @@ public class CryptoObject{ self.encryptionState = encState self.signKey = signKey self.encType = encType + self.passcode = nil } diff --git a/enzevalos_iphone/Cryptography.swift b/enzevalos_iphone/Cryptography.swift index 8429f66554259ecab5b794bc753cb398484efaa2..e7fc0c1577a20513f36a5a4375307abe7cbc085e 100644 --- a/enzevalos_iphone/Cryptography.swift +++ b/enzevalos_iphone/Cryptography.swift @@ -15,10 +15,12 @@ public protocol Encryption{ func importKeys(key: String, isSecretKey: Bool, autocrypt: Bool) -> [String] func importKeys(data: Data, secret: Bool) -> [String] func importKeysFromFile(file: String) -> [String] + func exportKey(id: String, isSecretkey: Bool, autocrypt: Bool) -> String? + func exportKeyData(id: String, isSecretkey: Bool, autocrypt: Bool) -> Data? // operations on keys func encrypt(plaintext: String, ids: [String], myId: String) -> CryptoObject func decrypt(data: Data, decryptionId: String?, verifyIds: [String]) -> CryptoObject - + } diff --git a/enzevalos_iphone/ExportViewController.swift b/enzevalos_iphone/ExportViewController.swift index 4c4f904298f904ec3200aa70155c6e996c5177d4..3cc4f8a809afc83f09082a022c96aa1ce91cb6db 100644 --- a/enzevalos_iphone/ExportViewController.swift +++ b/enzevalos_iphone/ExportViewController.swift @@ -16,27 +16,22 @@ class ExportViewController: UITableViewController { @IBAction func buttonTouched(_ sender: Any) { if !alreadySent { //TODO: create passcode for AES, export key, send mail + let handler = DataHandler.handler let ids = handler.findSecretKeys() if ids.count > 0{ - // let id = ids[0] - // let pgp = SwiftPGP() - //passcode = loadPassword(id) + let id = ids[0] + let pgp = SwiftPGP() //AppDelegate.mailhandler.sendSecretKey(id) - let objPGP = ObjectivePGP() - if let data = "hello Bob".data(using: .utf8){ - print("Create Key message") - passcode = "1234" - let m = try! objPGP.symmetricEncrypt(data, signWith: nil, encryptionKey: passcode, passphrase: passcode, armored: true) - let mString = String.init(data: m, encoding: .utf8) - print(mString ?? "no encrypted message") - let p = try! objPGP.symmetricDecrypt(m, key: passcode, verifyWith: nil, signed: nil, valid: nil, integrityProtected: nil) - let pString = String.init(data: p, encoding: .utf8) - print(pString ?? "no decrypted message") + if let keyId = id.keyID{ + if let message = pgp.exportKeyData(id: keyId, isSecretkey: true, autocrypt: true){ + passcode = pgp.loadExportPasscode(id: keyId)! + print("My passcode: \(passcode)") + let mailHandler = AppDelegate.getAppDelegate().mailHandler + mailHandler.sendSecretKey(keyData: message, passcode: passcode, callback: mailSend) + } } - - } else{ // TODO: Error NO SECRET KEY! @@ -112,4 +107,14 @@ class ExportViewController: UITableViewController { tableView.estimatedRowHeight = 140 navigationItem.rightBarButtonItem?.title = NSLocalizedString("Done", comment: "") } + + func mailSend(_ error: Error?) { + if (error != nil) { + NSLog("Error sending email: \(String(describing: error))") + AppDelegate.getAppDelegate().showMessage("An error occured", completion: nil) + } else { + NSLog("Send successful!") + } + } + } diff --git a/enzevalos_iphone/Info.plist b/enzevalos_iphone/Info.plist index 542644078548014dbd4dcd371e8e3bb10899cfeb..c4d555c43168fd4ea98263b96924b8d6cded5f3f 100644 --- a/enzevalos_iphone/Info.plist +++ b/enzevalos_iphone/Info.plist @@ -5,7 +5,7 @@ <key>CFBundleDevelopmentRegion</key> <string>en</string> <key>CFBundleDisplayName</key> - <string>Enzevalos</string> + <string>Letterbox</string> <key>CFBundleExecutable</key> <string>$(EXECUTABLE_NAME)</string> <key>CFBundleIdentifier</key> @@ -17,11 +17,11 @@ <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> - <string>1.0</string> + <string>0.5</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> - <string>1</string> + <string>0.5</string> <key>LSRequiresIPhoneOS</key> <true/> <key>NSAppTransportSecurity</key> diff --git a/enzevalos_iphone/MailHandler.swift b/enzevalos_iphone/MailHandler.swift index 6fe99b650bba62ea814724a54be95f72ab82f8f2..f587d2831a6169a7ff606a5e6aa1435b772dceb9 100644 --- a/enzevalos_iphone/MailHandler.swift +++ b/enzevalos_iphone/MailHandler.swift @@ -230,8 +230,39 @@ class MailHandler { return ids } - func sendSecretKey(keyID: String){ - + func sendSecretKey(keyData: Data, passcode: String, callback: @escaping (Error?) -> Void){ + let useraddr = (UserManager.loadUserValue(Attribute.userAddr) as! String) + let session = createSMTPSession() + let builder = MCOMessageBuilder() + let userID :MCOAddress = MCOAddress(displayName: useraddr, mailbox: useraddr) + + createHeader(builder, toEntrys: [useraddr], ccEntrys: [], bccEntrys: [], subject: "Autocrypt Setup Message 2") + builder.header.setExtraHeaderValue("v0", forName: "Autocrypt-Setup-Message") + + + /* + if let key = MCOAttachment.init(rfc822Message: keyData){ + print("ID: \(key.contentID)") + print("Type: \(key.mimeType)") + // Use and test later: + // see https://autocrypt.readthedocs.io/en/latest/level1.html#autocrypt-setup-message + // key.mimeType = "application/autocrypt-key-backup" + key.mimeType = "application/pgp-encrypted" + builder.addAttachment(key) + } + let plain = MCOAttachment.init(text: "Klartext!") + builder.addAttachment(plain) + + */ + builder.addAttachment(MCOAttachment.init(text: NSLocalizedString("This message contains a secret for reading secure mails on other devices. \n 1) Input the passcode from your smartphone to unlock the message on your other device. \n 2) Import the secret into your pgp program on the device. \n\n For more information visit: www.enzevalos.de/other", comment: "Message when sending the secret key"))) + + let key = MCOAttachment.init(rfc822Message: keyData) + builder.addAttachment(key) + + + let sendOperation = session.sendOperation(with: builder.data() , from: userID, recipients: [userID]) + sendOperation?.start(callback) + createSendCopy(sendData: builder.openPGPEncryptedMessageData(withEncryptedData: keyData)) } @@ -267,8 +298,7 @@ class MailHandler { let cryptoObject = pgp.encrypt(plaintext: "\n" + message, ids: keyIDs, myId:sk.keyID!) if let encData = cryptoObject.chiphertext{ sendData = encData - builder.textBody = "Dies ist verschlüsselt!" - sendOperation = session.sendOperation(with: builder.openPGPEncryptedMessageData(withEncryptedData: sendData), from: userID, recipients: encPGP) + sendOperation = session.sendOperation(with: builder.openPGPEncryptedMessageData(withEncryptedData: sendData), from: userID, recipients: encPGP) //TODO handle different callbacks sendOperation.start(callback) @@ -360,8 +390,8 @@ class MailHandler { imapsession.port = UInt32(UserManager.loadUserValue(Attribute.imapPort) as! Int) imapsession.username = UserManager.loadUserValue(Attribute.userAddr) as! String imapsession.password = UserManager.loadUserValue(Attribute.userPW) as! String - imapsession.authType = UserManager.loadImapAuthType()//MCOAuthType(rawValue: UserManager.loadUserValue(Attribute.imapAuthType) as! Int) //MCOAuthType.SASLPlain - imapsession.connectionType = MCOConnectionType(rawValue: UserManager.loadUserValue(Attribute.imapConnectionType) as! Int)//MCOConnectionType.TLS + imapsession.authType = UserManager.loadImapAuthType() + imapsession.connectionType = MCOConnectionType(rawValue: UserManager.loadUserValue(Attribute.imapConnectionType) as! Int) let y = imapsession.folderStatusOperation("INBOX") y?.start{(error, status) -> Void in @@ -418,7 +448,7 @@ class MailHandler { session.port = UInt32(UserManager.loadUserValue(Attribute.smtpPort) as! Int) session.username = UserManager.loadUserValue(Attribute.userAddr) as! String session.password = UserManager.loadUserValue(Attribute.userPW) as! String - session.authType = UserManager.loadSmtpAuthType()//MCOAuthType(rawValue: UserManager.loadUserValue(Attribute.smtpAuthType) as! Int) + session.authType = UserManager.loadSmtpAuthType() session.connectionType = MCOConnectionType(rawValue: UserManager.loadUserValue(Attribute.smtpConnectionType) as! Int) return session } @@ -539,6 +569,16 @@ class MailHandler { if let _ = header?.extraHeaderValue(forName: AUTOCRYPTHEADER) { autocrypt = AutocryptContact(header: header!) } + + if let _ = header?.extraHeaderValue(forName: "Autocrypt-Setup-Message"){ + // own key export message -> Drop message?. + // TODO: Distinguish between other keys (future work) + if newMailCallback != nil{ + newMailCallback!() + } + return + } + if let to = header?.to { for r in to { diff --git a/enzevalos_iphone/SwiftPGP.swift b/enzevalos_iphone/SwiftPGP.swift index 77abf2170d7470161680971945e7e92da2f8693e..7cd46980e0dddf011913e97948d20e4a58626d2d 100644 --- a/enzevalos_iphone/SwiftPGP.swift +++ b/enzevalos_iphone/SwiftPGP.swift @@ -14,12 +14,17 @@ class SwiftPGP: Encryption{ let cryptoScheme = CryptoScheme.PGP + let PasscodeSize = 36 + private func generatePW(size: Int)-> String{ var pw = "" - for _ in 0..<size{ + for i in 0..<size{ let p = Int(arc4random_uniform(10)) pw.append(String(p)) + if i % 4 == 3 && i < size - 4{ + pw.append("-") + } } return pw } @@ -37,6 +42,12 @@ class SwiftPGP: Encryption{ } } + private var exportPwKeyChain: Keychain{ + get{ + return Keychain(service: "Enzevalos/PGP/ExportPassword") + } + } + private func storeKey(key: PGPKey) -> String{ let id = key.keyID.longKeyString let data = try! key.export() @@ -70,7 +81,18 @@ class SwiftPGP: Encryption{ return nil } - func loadPassword(id: String) -> String?{ + func loadExportPasscode(id: String) -> String?{ + do{ + if let pw = try exportPwKeyChain.getString(id){ + return pw + } + } catch{ + return nil + } + return nil + } + + private func loadPassword(id: String) -> String?{ do{ if let pw = try pwKeyChain.getString(id){ return pw @@ -83,7 +105,7 @@ class SwiftPGP: Encryption{ func generateKey(adr: String) -> String{ let gen = PGPKeyGenerator() - let pw = generatePW(size: 36) + let pw = generatePW(size: PasscodeSize) let key = gen.generate(for: adr, passphrase: pw) pwKeyChain[key.keyID.longKeyString] = pw return storeKey(key: key) @@ -99,7 +121,7 @@ class SwiftPGP: Encryption{ } else{ if let data = key.data(using: .utf8){ - keys = pgp.importKeys(from: data) //.base64EncodedData() + keys = pgp.importKeys(from: data) } else{ @@ -138,9 +160,40 @@ class SwiftPGP: Encryption{ } func exportKey(id: String, isSecretkey isSecretKey: Bool, autocrypt: Bool) -> String?{ + if let key = exportKeyData(id: id, isSecretkey: isSecretKey, autocrypt: autocrypt){ + if !isSecretKey && autocrypt{ + return key.base64EncodedString() + } + else{ + return String.init(data: key, encoding: .utf8) + } + } + return nil + } + + func exportKeyData(id: String, isSecretkey: Bool, autocrypt: Bool) -> Data?{ let pgp = ObjectivePGP() if var key = loadKey(id: id){ - if key.isSecret && !isSecretKey{ + if isSecretkey && key.isSecret{ + if let keyData = pgp.export(key, armored: true){ + if autocrypt{ + // Create Autocrypt Setup-message + // See: https://autocrypt.readthedocs.io/en/latest/level1.html#autocrypt-setup-message + var passcode = loadPassword(id: id) + if passcode == nil{ + passcode = generatePW(size: PasscodeSize) + } + exportPwKeyChain[key.keyID.longKeyString] = passcode + let cipher = try! pgp.symmetricEncrypt(keyData, signWith: nil, encryptionKey: passcode, passphrase: passcode, armored: true) + print(String.init(data: cipher, encoding: .utf8) ?? "NO KEY") + + return cipher + } + return keyData + } + } + + if key.isSecret && !isSecretkey{ let pk = try! key.export(PGPPartialKeyType.public, error: ()) let keys = pgp.keys(from: pk) if (keys.count > 0){ @@ -152,17 +205,18 @@ class SwiftPGP: Encryption{ } if autocrypt{ if let data = pgp.export(key, armored: false){ - return data.base64EncodedString() + return data } } else{ if let data = pgp.export(key, armored: true){ - return data.base64EncodedString() + return data } } } return nil } + func encrypt(plaintext: String, ids: [String], myId: String) -> CryptoObject{ let pgp = ObjectivePGP()