From 4ade9222f7bd7647ca6024fed7669f4b33ed00b0 Mon Sep 17 00:00:00 2001 From: SendSafely-GitHub Date: Tue, 28 Nov 2023 07:06:33 -0500 Subject: [PATCH] v3.0.8 - I18N support - TOTP code support - Add sub key to publicKey of PGP generatedKeyPair - Cleanup --- SendsafelyAPI/ClientAPI.cs | 25 +- SendsafelyAPI/EnterpriseInformation.cs | 7 + .../Exceptions/TwoFactorAuthException.cs | 40 +- SendsafelyAPI/Objects/Connection.cs | 22 + .../Objects/EnterpriseInformationResponse.cs | 8 + .../Objects/GenerateAPIKeyResponse.cs | 8 + SendsafelyAPI/Properties/AssemblyInfo.cs | 6 +- SendsafelyAPI/Utilities/CryptUtility.cs | 392 +++++++++--------- SendsafelyAPI/Utilities/EnterpriseUtility.cs | 1 + .../Utilities/RegistrationUtility.cs | 2 +- SendsafelyAPI/Utilities/StartupUtility.cs | 2 +- 11 files changed, 298 insertions(+), 215 deletions(-) diff --git a/SendsafelyAPI/ClientAPI.cs b/SendsafelyAPI/ClientAPI.cs index 40d4362..f68261a 100644 --- a/SendsafelyAPI/ClientAPI.cs +++ b/SendsafelyAPI/ClientAPI.cs @@ -15,6 +15,16 @@ namespace SendSafely public class ClientAPI { private Connection connection = null; + private String locale = "en-US"; + + public ClientAPI() { } + + public ClientAPI(string locale) + { + if (!String.IsNullOrEmpty(locale)) { + this.locale = locale; + } + } /// /// Initializes the API. This function must be called before the API can be used. @@ -40,6 +50,7 @@ public void InitialSetup(string host, string apiKey, string apiSecret, WebProxy { StartupUtility su = new StartupUtility(host, apiSecret, apiKey, proxy); this.connection = su.GetConnectionObject(); + this.connection.setLocale(this.locale); } /// @@ -51,6 +62,7 @@ public void InitialSetup(string host, string apiKey, string apiSecret, WebProxy public void InitialSetup(string host, WebProxy proxy) { this.connection = new Connection(host, proxy); + this.connection.setLocale(this.locale); } /// @@ -332,7 +344,7 @@ public void DeletePackage(String packageId) } /// - /// Deletes a temporary package, which is a package that has not yet been finalized. + /// (Deprecated) Deletes a temporary package, which is a package that has not yet been finalized. /// /// The unique package id of the package to be deleted. /// Thrown when the API has not been initialized. @@ -340,6 +352,7 @@ public void DeletePackage(String packageId) /// Thrown when the API failed to connect to the server. /// Thrown when a non-existent or invalid package ID is used. /// Will be thrown if the server returns an error message + [Obsolete("This version of DeleteTempPackage is deprecated. Instead please use DeletePackage.")] public void DeleteTempPackage(String packageId) { EnforceInitialized(); @@ -713,7 +726,6 @@ public String FinalizePackage(String packageId, String keycode) /// /// A link to access the package. This link can be sent to the recipients. /// - [Obsolete("This version of FinalizePackage is deprecated. Instead please use FinalizePackage which supports both allowReplyAll and notifyRecipients features.")] public String FinalizePackage(String packageId, String keycode, bool allowReplyAll) { EnforceInitialized(); @@ -1598,6 +1610,15 @@ public void SetOutlookVersion(String version) { this.connection.OutlookVersion = version; } + + /// + /// This method is intended for use by the SendSafely Outlook Plugin. Sets the name of the client application that is making the API request. + /// + /// Name of client application making the API request. + public void setRequestAPI(String requestAPI) + { + this.connection.RequestAPI = requestAPI; + } /// /// This method is intended for use by the SendSafely Outlook Plugin. Starts the registration process. If a valid email is provided, a validation code will be sent to the SendSafely servers. diff --git a/SendsafelyAPI/EnterpriseInformation.cs b/SendsafelyAPI/EnterpriseInformation.cs index 0b0d12c..b0c249a 100644 --- a/SendsafelyAPI/EnterpriseInformation.cs +++ b/SendsafelyAPI/EnterpriseInformation.cs @@ -12,6 +12,7 @@ public class EnterpriseInformation private bool allowUndisclosedRecipients; private bool outlookBeta; private bool messageEncryption; + private bool allowI18nAll; public String Host { @@ -43,5 +44,11 @@ public bool MessageEncryption set { messageEncryption = value; } } + public bool AllowI18nAll + { + get { return allowI18nAll; } + set { allowI18nAll = value; } + } + } } diff --git a/SendsafelyAPI/Exceptions/TwoFactorAuthException.cs b/SendsafelyAPI/Exceptions/TwoFactorAuthException.cs index ce5a8b7..1ab0b42 100644 --- a/SendsafelyAPI/Exceptions/TwoFactorAuthException.cs +++ b/SendsafelyAPI/Exceptions/TwoFactorAuthException.cs @@ -1,27 +1,35 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace SendSafely.Exceptions -{ - /// - /// Thrown when two factor authentication is required. The exception contains a ValidationToken parameter that must be used when validating the 2FA Code. - /// - [Serializable] - public class TwoFactorAuthException : BaseException +using System; +using System.Collections.Generic; +using System.Text; + +namespace SendSafely.Exceptions +{ + /// + /// Thrown when two factor authentication is required. The exception contains a ValidationToken parameter that must be used when validating the 2FA Code. + /// + [Serializable] + public class TwoFactorAuthException : BaseException { private String _validationToken; + private String _twoFaType; - public TwoFactorAuthException(String validationToken) + public TwoFactorAuthException(String validationToken, String twoFaType) { - this._validationToken = validationToken; + this._validationToken = validationToken; + this._twoFaType = twoFaType; } public String ValidationToken { get { return _validationToken; } set { _validationToken = value; } - } - } -} + } + + public String TwoFaType + { + get { return _twoFaType; } + set { _twoFaType = value; } + } + } +} diff --git a/SendsafelyAPI/Objects/Connection.cs b/SendsafelyAPI/Objects/Connection.cs index 121ef45..1657b7a 100644 --- a/SendsafelyAPI/Objects/Connection.cs +++ b/SendsafelyAPI/Objects/Connection.cs @@ -24,7 +24,11 @@ internal class Connection private String apiKeyHeadervalue = "ss-api-key"; private String apiTimestampHeadervalue = "ss-request-timestamp"; private String apiSignatureHeadervalue = "ss-request-signature"; + private String acceptLanguageHeaderValue = "Accept-Language"; + private String apiIntegrationTypeHeadervalue = "ss-request-api"; private String outlookVersion = null; + private String requestAPI = null; + private String locale = "en-US"; #region Constructors @@ -55,6 +59,12 @@ public String OutlookVersion set { outlookVersion = value; } } + public String RequestAPI + { + get { return requestAPI; } + set { requestAPI = value; } + } + public String ApiHost { get { return url; } @@ -137,6 +147,7 @@ public HttpWebRequest GetRequestforFileUpload(Endpoint p, String boundary, Strin wrReq.Headers.Add(apiSignatureHeadervalue, signature); wrReq.Headers.Add(apiTimestampHeadervalue, dateStr); + wrReq.Headers.Add(acceptLanguageHeaderValue, locale); wrReq.Method = p.Method.ToString(); wrReq.ContentType = p.ContentType + "; boundary=" + boundary; @@ -182,6 +193,12 @@ public Stream CallServer(Endpoint p, Object request) wrReq.Headers.Add(apiSignatureHeadervalue, signature); } wrReq.Headers.Add(apiTimestampHeadervalue, dateStr); + wrReq.Headers.Add(acceptLanguageHeaderValue, locale); + + if (!String.IsNullOrEmpty(requestAPI)) + { + wrReq.Headers.Add(apiIntegrationTypeHeadervalue, requestAPI); + } if (proxy != null) { @@ -199,6 +216,11 @@ public Stream CallServer(Endpoint p, Object request) return objStream; } + public void setLocale(String locale) + { + this.locale = locale; + } + #endregion #region Private Functions diff --git a/SendsafelyAPI/Objects/EnterpriseInformationResponse.cs b/SendsafelyAPI/Objects/EnterpriseInformationResponse.cs index 0c9dc49..3edfbbf 100644 --- a/SendsafelyAPI/Objects/EnterpriseInformationResponse.cs +++ b/SendsafelyAPI/Objects/EnterpriseInformationResponse.cs @@ -14,6 +14,7 @@ class EnterpriseInformationResponse private bool _allowUndisclosedRecipients; private bool _outlookBeta; private bool _messageEncryption; + private bool _allowI18nAll; [JsonProperty(PropertyName = "host")] public String Host @@ -49,5 +50,12 @@ public bool MessageEncryption get { return _messageEncryption; } set { _messageEncryption = value; } } + + [JsonProperty(PropertyName = "allowI18nAll")] + public bool AllowI18nAll + { + get { return _allowI18nAll; } + set { _allowI18nAll = value; } + } } } diff --git a/SendsafelyAPI/Objects/GenerateAPIKeyResponse.cs b/SendsafelyAPI/Objects/GenerateAPIKeyResponse.cs index aea1703..1ac63f6 100644 --- a/SendsafelyAPI/Objects/GenerateAPIKeyResponse.cs +++ b/SendsafelyAPI/Objects/GenerateAPIKeyResponse.cs @@ -14,6 +14,7 @@ class GenerateAPIKeyResponse private String _email; private String _apiKey; private String _apiSecret; + private String _twoFaType; [JsonProperty(PropertyName = "response")] internal APIResponse Response @@ -49,5 +50,12 @@ public String APISecret get { return _apiSecret; } set { _apiSecret = value; } } + + [JsonProperty(PropertyName = "twoFaType")] + public String TwoFaType + { + get { return _twoFaType; } + set { _twoFaType = value; } + } } } diff --git a/SendsafelyAPI/Properties/AssemblyInfo.cs b/SendsafelyAPI/Properties/AssemblyInfo.cs index dcc3069..eef8034 100644 --- a/SendsafelyAPI/Properties/AssemblyInfo.cs +++ b/SendsafelyAPI/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SendSafely Windows Client API")] -[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,7 +32,7 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.7")] -[assembly: AssemblyFileVersion("3.0.7")] +[assembly: AssemblyVersion("3.0.8")] +[assembly: AssemblyFileVersion("3.0.8")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("APITests")] \ No newline at end of file diff --git a/SendsafelyAPI/Utilities/CryptUtility.cs b/SendsafelyAPI/Utilities/CryptUtility.cs index 08b05a1..aa47f11 100644 --- a/SendsafelyAPI/Utilities/CryptUtility.cs +++ b/SendsafelyAPI/Utilities/CryptUtility.cs @@ -1,49 +1,41 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Security.Cryptography; -using System.IO; -using Org.BouncyCastle.Bcpg.OpenPgp; -using Org.BouncyCastle.Bcpg; -using SendSafely.Objects; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Macs; -using Org.BouncyCastle.Crypto; +using System; +using System.Text; +using System.Security.Cryptography; +using System.IO; +using Org.BouncyCastle.Bcpg.OpenPgp; +using Org.BouncyCastle.Bcpg; +using SendSafely.Objects; +using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; using SendSafely.Exceptions; using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto.Prng; -using Org.BouncyCastle.Asn1.Pkcs; -using Org.BouncyCastle.Pkcs; -using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.X509; - -namespace SendSafely.Utilities -{ - public class CryptUtility - { - public String GenerateToken() - { - byte[] randomBytes = new byte[32]; - RNGCryptoServiceProvider prng = new RNGCryptoServiceProvider(); - prng.GetBytes(randomBytes); - - return EncodingUtil.Base64Encode(randomBytes); - } - - public void EncryptFile(FileInfo encryptedFile, FileInfo inputFile, String filename, char[] passPhrase, ISendSafelyProgress progress) - { - using (FileStream outStream = encryptedFile.OpenWrite()) - { - PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Aes256, true); - cPk.AddMethod(passPhrase); - using (Stream cOut = cPk.Open(outStream, new byte[1 << 16])) - { - WriteFileToLiteralData(cOut, PgpLiteralData.Binary, inputFile, filename, inputFile.Length); - } - } +using Org.BouncyCastle.Bcpg.Sig; + +namespace SendSafely.Utilities +{ + public class CryptUtility + { + public String GenerateToken() + { + byte[] randomBytes = new byte[32]; + RNGCryptoServiceProvider prng = new RNGCryptoServiceProvider(); + prng.GetBytes(randomBytes); + + return EncodingUtil.Base64Encode(randomBytes); + } + + public void EncryptFile(FileInfo encryptedFile, FileInfo inputFile, String filename, char[] passPhrase, ISendSafelyProgress progress) + { + using (FileStream outStream = encryptedFile.OpenWrite()) + { + PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Aes256, true); + cPk.AddMethod(passPhrase); + using (Stream cOut = cPk.Open(outStream, new byte[1 << 16])) + { + WriteFileToLiteralData(cOut, PgpLiteralData.Binary, inputFile, filename, inputFile.Length); + } + } } public void DecryptFile(Stream outStream, Stream inputStream, char[] passPhrase) @@ -144,41 +136,41 @@ public String DecryptMessage(String encryptedMessage, char[] passPhrase) } return message; - } - - public String EncryptMessage(String unencryptedMessage, char[] passPhrase) - { - // Convert the input to a byte array. We expect the string to be UTF-8 encoded - byte[] unencryptedByteArray = System.Text.Encoding.UTF8.GetBytes (unencryptedMessage); - - PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator(); - - // Write the data to a literal - MemoryStream bOut; - using (bOut = new MemoryStream() ) - { - using (Stream pOut = lData.Open(bOut, PgpLiteralData.Binary, PgpLiteralData.Console, unencryptedByteArray.Length, DateTime.Now )) - { - pOut.Write(unencryptedByteArray, 0, unencryptedByteArray.Length); - } - } - lData.Close(); - - PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Aes256, true); - cPk.AddMethod(passPhrase); - - byte[] bytes = bOut.ToArray(); - - MemoryStream encOut; - using (encOut = new MemoryStream()) - { - using (Stream cOut = cPk.Open(encOut, bytes.Length) ) - { - cOut.Write(bytes, 0, bytes.Length); - } - } - - return Convert.ToBase64String(encOut.ToArray()); + } + + public String EncryptMessage(String unencryptedMessage, char[] passPhrase) + { + // Convert the input to a byte array. We expect the string to be UTF-8 encoded + byte[] unencryptedByteArray = System.Text.Encoding.UTF8.GetBytes (unencryptedMessage); + + PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator(); + + // Write the data to a literal + MemoryStream bOut; + using (bOut = new MemoryStream() ) + { + using (Stream pOut = lData.Open(bOut, PgpLiteralData.Binary, PgpLiteralData.Console, unencryptedByteArray.Length, DateTime.Now )) + { + pOut.Write(unencryptedByteArray, 0, unencryptedByteArray.Length); + } + } + lData.Close(); + + PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Aes256, true); + cPk.AddMethod(passPhrase); + + byte[] bytes = bOut.ToArray(); + + MemoryStream encOut; + using (encOut = new MemoryStream()) + { + using (Stream cOut = cPk.Open(encOut, bytes.Length) ) + { + cOut.Write(bytes, 0, bytes.Length); + } + } + + return Convert.ToBase64String(encOut.ToArray()); } public String EncryptKeycode(String publicKeyStr, String unencryptedKeycode) @@ -299,10 +291,7 @@ public String DecryptKeycode(String privateKeyStr, String encryptedKeycode) public Keypair GenerateKeyPair(String email) { - RsaKeyPairGenerator kpgen = new RsaKeyPairGenerator(); - kpgen.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 2048)); - - AsymmetricCipherKeyPair keyPair = kpgen.GenerateKeyPair(); + AsymmetricCipherKeyPair keyPair = generateAsymmetricCipherKeyPair(); Keypair pair = Armor(keyPair, email); return pair; @@ -316,28 +305,39 @@ private Keypair Armor(AsymmetricCipherKeyPair keyPair, String email) MemoryStream memOut = new MemoryStream(); ArmoredOutputStream secretOut = new ArmoredOutputStream(memOut); - PgpSecretKey secretKey = new PgpSecretKey( + AsymmetricCipherKeyPair subKeyPair = generateAsymmetricCipherKeyPair(); + PgpSignatureSubpacketGenerator subPackets = new PgpSignatureSubpacketGenerator(); + subPackets.SetKeyFlags(false,KeyFlags.Authentication | KeyFlags.CertifyOther | KeyFlags.SignData); + subPackets.SetKeyExpirationTime(false, 0); + + PgpKeyPair pgpMasterKey = new PgpKeyPair(PublicKeyAlgorithmTag.RsaGeneral, publicKey, privateKey, DateTime.Now); + PgpKeyPair pgpSubKey = new PgpKeyPair(PublicKeyAlgorithmTag.RsaGeneral, subKeyPair.Public, subKeyPair.Private, DateTime.Now); + + PgpKeyRingGenerator pgpGenerator = new PgpKeyRingGenerator( PgpSignature.DefaultCertification, - PublicKeyAlgorithmTag.RsaGeneral, - publicKey, - privateKey, - DateTime.Now, - email, + pgpMasterKey, + email, SymmetricKeyAlgorithmTag.Null, + new char[0], + false, + subPackets.Generate(), null, - null, - null, - new SecureRandom() - ); + new SecureRandom()); + + subPackets = new PgpSignatureSubpacketGenerator(); + subPackets.SetKeyExpirationTime(false, 0); + subPackets.SetKeyFlags(false, KeyFlags.EncryptStorage | KeyFlags.EncryptComms); + pgpGenerator.AddSubKey(pgpSubKey, subPackets.Generate(), null); + PgpSecretKeyRing secretKey = pgpGenerator.GenerateSecretKeyRing(); + PgpPublicKeyRing key = pgpGenerator.GeneratePublicKeyRing(); + secretKey.Encode(secretOut); secretOut.Close(); MemoryStream memPublicOut = new MemoryStream(); Stream publicOut = new ArmoredOutputStream(memPublicOut); - - PgpPublicKey key = secretKey.PublicKey; - + key.Encode(publicOut); publicOut.Close(); @@ -350,79 +350,87 @@ private Keypair Armor(AsymmetricCipherKeyPair keyPair, String email) pair.PublicKey = publicKeyStr; return pair; - } - - public String pbkdf2(String value, String salt, int iterations) - { - String hash = EncodingUtil.HexEncode(PBKDF2Sha256GetBytes( - 32, - System.Text.Encoding.UTF8.GetBytes(value), - System.Text.Encoding.UTF8.GetBytes(salt), - iterations)); - - return hash; - } - - public String createSignature(String key, String data) - { - byte[] keyBytes = System.Text.Encoding.UTF8.GetBytes(key); - byte[] hashValue; - using (HMACSHA256 hmac = new HMACSHA256(keyBytes)) - { - hashValue = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(data)); - } - return EncodingUtil.HexEncode(hashValue); - } - - private byte[] PBKDF2Sha256GetBytes(int dklen, byte[] password, byte[] salt, int iterationCount) - { - using (var hmac = new System.Security.Cryptography.HMACSHA256(password)) - { - int hashLength = hmac.HashSize / 8; - if ((hmac.HashSize & 7) != 0) - hashLength++; - int keyLength = dklen / hashLength; - if ((long)dklen > (0xFFFFFFFFL * hashLength) || dklen < 0) - throw new ArgumentOutOfRangeException("dklen"); - if (dklen % hashLength != 0) - keyLength++; - byte[] extendedkey = new byte[salt.Length + 4]; - Buffer.BlockCopy(salt, 0, extendedkey, 0, salt.Length); - using (var ms = new System.IO.MemoryStream()) - { - for (int i = 0; i < keyLength; i++) - { - extendedkey[salt.Length] = (byte)(((i + 1) >> 24) & 0xFF); - extendedkey[salt.Length + 1] = (byte)(((i + 1) >> 16) & 0xFF); - extendedkey[salt.Length + 2] = (byte)(((i + 1) >> 8) & 0xFF); - extendedkey[salt.Length + 3] = (byte)(((i + 1)) & 0xFF); - byte[] u = hmac.ComputeHash(extendedkey); - Array.Clear(extendedkey, salt.Length, 4); - byte[] f = u; - for (int j = 1; j < iterationCount; j++) - { - u = hmac.ComputeHash(u); - for (int k = 0; k < f.Length; k++) - { - f[k] ^= u[k]; - } - } - ms.Write(f, 0, f.Length); - Array.Clear(u, 0, u.Length); - Array.Clear(f, 0, f.Length); - } - byte[] dk = new byte[dklen]; - ms.Position = 0; - ms.Read(dk, 0, dklen); - ms.Position = 0; - for (long i = 0; i < ms.Length; i++) - { - ms.WriteByte(0); - } - Array.Clear(extendedkey, 0, extendedkey.Length); - return dk; - } - } + } + + private AsymmetricCipherKeyPair generateAsymmetricCipherKeyPair() + { + RsaKeyPairGenerator kpgen = new RsaKeyPairGenerator(); + kpgen.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 2048)); + AsymmetricCipherKeyPair keyPair = kpgen.GenerateKeyPair(); + return keyPair; + } + + public String pbkdf2(String value, String salt, int iterations) + { + String hash = EncodingUtil.HexEncode(PBKDF2Sha256GetBytes( + 32, + System.Text.Encoding.UTF8.GetBytes(value), + System.Text.Encoding.UTF8.GetBytes(salt), + iterations)); + + return hash; + } + + public String createSignature(String key, String data) + { + byte[] keyBytes = System.Text.Encoding.UTF8.GetBytes(key); + byte[] hashValue; + using (HMACSHA256 hmac = new HMACSHA256(keyBytes)) + { + hashValue = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(data)); + } + return EncodingUtil.HexEncode(hashValue); + } + + private byte[] PBKDF2Sha256GetBytes(int dklen, byte[] password, byte[] salt, int iterationCount) + { + using (var hmac = new System.Security.Cryptography.HMACSHA256(password)) + { + int hashLength = hmac.HashSize / 8; + if ((hmac.HashSize & 7) != 0) + hashLength++; + int keyLength = dklen / hashLength; + if ((long)dklen > (0xFFFFFFFFL * hashLength) || dklen < 0) + throw new ArgumentOutOfRangeException("dklen"); + if (dklen % hashLength != 0) + keyLength++; + byte[] extendedkey = new byte[salt.Length + 4]; + Buffer.BlockCopy(salt, 0, extendedkey, 0, salt.Length); + using (var ms = new System.IO.MemoryStream()) + { + for (int i = 0; i < keyLength; i++) + { + extendedkey[salt.Length] = (byte)(((i + 1) >> 24) & 0xFF); + extendedkey[salt.Length + 1] = (byte)(((i + 1) >> 16) & 0xFF); + extendedkey[salt.Length + 2] = (byte)(((i + 1) >> 8) & 0xFF); + extendedkey[salt.Length + 3] = (byte)(((i + 1)) & 0xFF); + byte[] u = hmac.ComputeHash(extendedkey); + Array.Clear(extendedkey, salt.Length, 4); + byte[] f = u; + for (int j = 1; j < iterationCount; j++) + { + u = hmac.ComputeHash(u); + for (int k = 0; k < f.Length; k++) + { + f[k] ^= u[k]; + } + } + ms.Write(f, 0, f.Length); + Array.Clear(u, 0, u.Length); + Array.Clear(f, 0, f.Length); + } + byte[] dk = new byte[dklen]; + ms.Position = 0; + ms.Read(dk, 0, dklen); + ms.Position = 0; + for (long i = 0; i < ms.Length; i++) + { + ms.WriteByte(0); + } + Array.Clear(extendedkey, 0, extendedkey.Length); + return dk; + } + } } private PgpPrivateKey FindKeyById(PgpSecretKeyRingBundle privRings, long keyId) @@ -435,28 +443,28 @@ private PgpPrivateKey FindKeyById(PgpSecretKeyRingBundle privRings, long keyId) } return pgpSecKey.ExtractPrivateKey(null); - } - - private void WriteFileToLiteralData(Stream pOut, char format, FileInfo dataToRead, String filename, long fileSize) - { - //PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator(); - //OutputStream pOut = lData.open(out, fileType, filename, filesize, new Date()); - PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator(); - //lData.Open(pOut, format, dataToRead); - - using (Stream lOut = lData.Open(pOut, format, filename, fileSize, DateTime.Now)) - { - using (Stream inputStream = dataToRead.OpenRead()) - { - - byte[] buf = new byte[1 << 16]; - int len; - while ((len = inputStream.Read(buf, 0, buf.Length)) > 0) - { - lOut.Write(buf, 0, len); - } - } - } - } - } -} + } + + private void WriteFileToLiteralData(Stream pOut, char format, FileInfo dataToRead, String filename, long fileSize) + { + //PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator(); + //OutputStream pOut = lData.open(out, fileType, filename, filesize, new Date()); + PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator(); + //lData.Open(pOut, format, dataToRead); + + using (Stream lOut = lData.Open(pOut, format, filename, fileSize, DateTime.Now)) + { + using (Stream inputStream = dataToRead.OpenRead()) + { + + byte[] buf = new byte[1 << 16]; + int len; + while ((len = inputStream.Read(buf, 0, buf.Length)) > 0) + { + lOut.Write(buf, 0, len); + } + } + } + } + } +} diff --git a/SendsafelyAPI/Utilities/EnterpriseUtility.cs b/SendsafelyAPI/Utilities/EnterpriseUtility.cs index 49f5bd7..4c0933d 100644 --- a/SendsafelyAPI/Utilities/EnterpriseUtility.cs +++ b/SendsafelyAPI/Utilities/EnterpriseUtility.cs @@ -32,6 +32,7 @@ public EnterpriseInformation GetInformation() info.AllowUndisclosedRecipients = response.AllowUndisclosedRecipients; info.OutlookBeta = response.OutlookBeta; info.MessageEncryption = response.MessageEncryption; + info.AllowI18nAll = response.AllowI18nAll; return info; } diff --git a/SendsafelyAPI/Utilities/RegistrationUtility.cs b/SendsafelyAPI/Utilities/RegistrationUtility.cs index 021f01b..b7163ea 100644 --- a/SendsafelyAPI/Utilities/RegistrationUtility.cs +++ b/SendsafelyAPI/Utilities/RegistrationUtility.cs @@ -222,7 +222,7 @@ public APICredential GenerateAPIKey(String username, String password, String key if (response.Response == APIResponse.TWO_FA_REQUIRED) { - throw new TwoFactorAuthException(response.Message); + throw new TwoFactorAuthException(response.Message, response.TwoFaType); } else if (response.Response == APIResponse.AUTHENTICATION_FAILED) { diff --git a/SendsafelyAPI/Utilities/StartupUtility.cs b/SendsafelyAPI/Utilities/StartupUtility.cs index 46e05bf..8a669ce 100644 --- a/SendsafelyAPI/Utilities/StartupUtility.cs +++ b/SendsafelyAPI/Utilities/StartupUtility.cs @@ -39,7 +39,7 @@ public StartupUtility(String host, String privateKey, String apiKey, WebProxy pr public Objects.Version VerifyVersion() { Endpoint p = ConnectionStrings.Endpoints["version"].Clone(); - String version = (ConfigurationManager.AppSettings["version"] != null) ? ConfigurationManager.AppSettings["version"] : "0.3"; + String version = "0.3"; p.Path = p.Path.Replace("{version}", version); VersionResponse response = connection.Send(p);