/// <summary>Encrypts password using IBM's flavor of DES algorithm as defined in RFC2877</summary>
        /// <param name="userName">User name in ASCII</param>
        /// <param name="password">Password in ASCII</param>
        /// <param name="serverSeed">Server's seed</param>
        /// <param name="clientSeed">Client's seed</param>
        /// <returns>Encrypted password as EBCDIC byte stream</returns>
        public static byte[] EncryptPasswordDES(string userName, string password, ulong serverSeed, ulong clientSeed)
        {
            byte[] passwordToken = new byte[8];
            if (password.Length > 8)
            {
                byte[] passwordTokenA = GenerateToken(userName, password.Substring(0, 8));
                byte[] passwordTokenB = GenerateToken(userName, password.Substring(8));
                passwordToken = Converters.UInt64ToBigEndian(Converters.BigEndianToUInt64(passwordTokenA) ^ Converters.BigEndianToUInt64(passwordTokenB));
            }
            else
            {
                passwordToken = GenerateToken(userName, password);
            }

            byte[] usernameEBCDIC_A;
            byte[] usernameEBCDIC_B;

            if (userName.Length <= 8)
            {
                usernameEBCDIC_A = Converters.AsciiToEbcdic(userName.ToUpper().PadRight(8));
                usernameEBCDIC_B = Converters.UInt64ToBigEndian(0x4040404040404040);
            }
            else
            {
                usernameEBCDIC_A = Converters.AsciiToEbcdic(userName.Substring(0, 8).ToUpper().PadRight(8));
                usernameEBCDIC_B = Converters.AsciiToEbcdic(userName.Substring(8).ToUpper().PadRight(8));
            }

            byte[] firstEncryptionRound  = EncryptDES(Converters.UInt64ToBigEndian(serverSeed + 1), passwordToken);
            byte[] secondEncryptionRound = EncryptDES(Converters.UInt64ToBigEndian(Converters.BigEndianToUInt64(firstEncryptionRound) ^ clientSeed), passwordToken);
            byte[] thirdEncryptionRound  = EncryptDES(Converters.UInt64ToBigEndian(Converters.BigEndianToUInt64(usernameEBCDIC_A) ^ (serverSeed + 1) ^ Converters.BigEndianToUInt64(secondEncryptionRound)), passwordToken);
            byte[] fourthEncryptionRound = EncryptDES(Converters.UInt64ToBigEndian(Converters.BigEndianToUInt64(usernameEBCDIC_B) ^ (serverSeed + 1) ^ Converters.BigEndianToUInt64(thirdEncryptionRound)), passwordToken);
            return(EncryptDES(Converters.UInt64ToBigEndian(Converters.BigEndianToUInt64(fourthEncryptionRound) ^ 0x0000000000000001), passwordToken));
        }
        /// <summary>Creates an intermediary password token using DES algorithm</summary>
        /// <param name="userName">User name in ASCII</param>
        /// <param name="password">Password in ASCII</param>
        /// <returns>Encrypted password token as EBCDIC byte stream</returns>
        private static byte[] GenerateToken(string userName, string password)
        {
            if (password.Length > 8)
            {
                throw new System.InvalidOperationException("Wrong method invocation: password cannot be longer than 8");
            }

            if (userName.Length > 10)
            {
                throw new System.InvalidOperationException("Wrong method invocation: user name cannot be longer than 10");
            }

            byte[] passwordEBCDIC = Converters.AsciiToEbcdic(password.ToUpper().PadRight(8));

            byte[] encryptionKey = Converters.UInt64ToBigEndian((Converters.BigEndianToUInt64(passwordEBCDIC) ^ 0x5555555555555555) << 1);

            byte[] usernameEBCDIC = PrepareUserNameDES(userName);

            return(EncryptDES(usernameEBCDIC, encryptionKey));
        }
Exemple #3
0
        //-----------------------------------------------------------------------
        // Private methods
        //-----------------------------------------------------------------------

        /// <summary>Connects to the Sign-on Verify server</summary>
        private void ConnectToSignonVerifyServer()
        {
            // Establish authentication channel
            this.socketConnectorSignonVerify = new SocketConnector(this.serverName, this.useSSL ? TcpPortSignonVerifySSL : TcpPortSignonVerify, this.useSSL, this.ignoreSelfSignedCertificates);

            // Default current seed information
            this.clientSeed = 0;
            this.serverSeed = 0;

            // Exchange random seeds
            ulong clientSeed = (ulong)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
            BigEndianMemoryStream outputStream = new BigEndianMemoryStream();

            ////           outputStream.WriteInt(52); // length
            outputStream.WriteShort(0);                    // Header ID (0)
            outputStream.WriteShort(ServerIDSignonVerify); // Server ID
            outputStream.WriteInt(0);                      // CS instance
            outputStream.WriteInt(0);                      // Correlation ID
            outputStream.WriteShort(0);                    // Template length
            outputStream.WriteShort(0x7003);               // ReqReP ID
            outputStream.WriteInt(10);                     // Client version LL
            outputStream.WriteShort(0x1101);               // Client version CP
            outputStream.WriteInt(1);                      // Client version
            outputStream.WriteInt(8);                      // Client data stream level LL
            outputStream.WriteShort(0x1102);               // Client datastream level CP
            outputStream.WriteShort(2);                    // Client datastream level
            outputStream.WriteInt(14);                     // Client seed LL
            outputStream.WriteShort(0x1103);               // Client seed CP
            outputStream.WriteLong(clientSeed);            // Client seed
            this.socketConnectorSignonVerify.Write(outputStream.ToArray());

            // Retrieve server response
            byte[] response = this.socketConnectorSignonVerify.Read();
            BigEndianMemoryStream inputStream = new BigEndianMemoryStream();

            inputStream.Write(response, 0, response.Length);

            /*
             *  The response comes  in the following format:
             *
             *  Offset (byte)       Information         Length (byte)
             *  -----------------------------------------------------------
             *  Fixed header
             *  -----------------------------------------------------------
             *  0                   Response length     4
             *  4                   (Reserved)          16
             *  20                  Result code         4
             *  24                  (Dynamic fields)    see below
             *  -----------------------------------------------------------
             *  Dynamic fields (Offset is dynamic)
             *  -----------------------------------------------------------
             *  0                   Field length        4
             *  4                   Field code          2
             *  6                   Field data          (Field length - 6)
             */

            // Read fixed header
            inputStream.Position = 0;
            uint responseLength = inputStream.ReadInt();

            if (responseLength < 20)
            {
                throw new System.InvalidOperationException("Seeds exchange failed. Bad response length.");
            }

            inputStream.Position += 16;

            uint resultCode = inputStream.ReadInt();

            if (resultCode != 0)
            {
                throw new System.InvalidOperationException("Seeds exchange failed. Bad return code.");
            }

            while (inputStream.Position < responseLength)
            {
                uint   dynamicFieldLength = inputStream.ReadInt();
                ushort dynamicFieldCode   = inputStream.ReadShort();
                byte[] dynamicFieldData   = new byte[dynamicFieldLength - 6];
                inputStream.Read(dynamicFieldData, 0, (int)dynamicFieldLength - 6);

                switch (dynamicFieldCode)
                {
                case 0x1101:        // Server Version
                    this.serverVersion = Converters.BigEndianToUInt32(dynamicFieldData);
                    break;

                case 0x1102:        // Server Level
                    this.serverLevel = Converters.BigEndianToUInt16(dynamicFieldData);
                    break;

                case 0x1103:        // Server Seed
                    this.serverSeed = Converters.BigEndianToUInt64(dynamicFieldData);
                    break;

                case 0x1119:        // Password Level
                    this.passwordLevel = Converters.BigEndianToUInt8(dynamicFieldData);
                    break;

                case 0x111F:        // Job Name
                    this.jobName = Converters.EbcdicToAsciiString(dynamicFieldData, 4);
                    break;

                default:
                    break;
                }
            }

            Debug.WriteLine("Seeds were exchanged, return code is 0x" + resultCode.ToString("X8"));

            this.clientSeed = clientSeed;
        }
 /// <summary>Reads a long value from the stream</summary>
 /// <returns>A long value</returns>
 public ulong ReadLong()
 {
     byte[] longArray = new byte[8];
     this.Read(longArray, 0, 8);
     return(Converters.BigEndianToUInt64(longArray));
 }
Exemple #5
0
        //-----------------------------------------------------------------------
        // Class methods
        //-----------------------------------------------------------------------

        /// <summary>Returns password hash of the specified user, in specified format</summary>
        /// <param name="system">System to be connected to</param>
        /// <param name="userName">User name</param>
        /// <param name="hashType">Predefined password hash type (see documentation for details)</param>
        /// <returns>Password hash as a hex string</returns>
        public string GetEncryptedPassword(string userName, int hashType)
        {
            /*
             *  http://publib.boulder.ibm.com/infocenter/iseries/v5r4/index.jsp?topic=%2Fapis%2Fqsyrupwd.htm
             *
             *  Required Parameter Group:
             *
             *   1   Receiver variable              Output   Char(*) - 2000B
             *   2   Length of receiver variable    Input    Binary(4)
             *   3   Format                         Input    Char(8) - "UPWD0100"
             *   4   User profile name              Input    Char(10) - userName
             *   5   Error code                     I/O      Char(*)
             */

            ProgramCallParameters qsyrupwdCallParameters =
                new ProgramCallParameters(5)
            {
                [0] = new ProgramCallParameter(
                    ProgramCallParameter.ParameterTypeOutput,
                    null,
                    2000),
                [1] = new ProgramCallParameter(
                    ProgramCallParameter.ParameterTypeInput,
                    Converters.UInt32ToBigEndian(2000)),
                [2] = new ProgramCallParameter(
                    ProgramCallParameter.ParameterTypeInput,
                    Converters.AsciiToEbcdic("UPWD0100")),
                [3] = new ProgramCallParameter(
                    ProgramCallParameter.ParameterTypeInput,
                    Converters.AsciiToEbcdic(userName.ToUpper().PadRight(10))),
                [4] = new ProgramCallParameter(
                    ProgramCallParameter.ParameterTypeInputOutput,
                    null,
                    500)
            };
            CallMessages qsyrupwdCallMessages = new CallMessages();

            if (CallProgram("QSYRUPWD", "QSYS", ref qsyrupwdCallParameters, ref qsyrupwdCallMessages) != 0)
            {
                foreach (CallMessage outputMessage in qsyrupwdCallMessages)
                {
                    Debug.WriteLine(outputMessage.MessageText);
                }
                throw new System.InvalidOperationException("The method GetEncryptedPassword failed. Check debug information.");
            }


            switch (hashType)
            {
            case PASSWORD_HASH_ALLDATA:     // All data
                return(Converters.BigEndianToHexString(qsyrupwdCallParameters[0].ParameterValue, 1, 269));

            case PASSWORD_HASH_UNKNOWNHASH:     // Unknown (hash?) data
                return(Converters.BigEndianToHexString(qsyrupwdCallParameters[0].ParameterValue, 78, 192));

            case PASSWORD_HASH_HMACSHA1MC:     // HMAC-SHA1 password (mixed case)
                return(Converters.BigEndianToHexString(qsyrupwdCallParameters[0].ParameterValue, 35, 20));

            case PASSWORD_HASH_HMACSHA1UC:     // HMAC-SHA1 password (uppercase)
                return(Converters.BigEndianToHexString(qsyrupwdCallParameters[0].ParameterValue, 55, 20));

            case PASSWORD_HASH_LMHASH:     // LM hash
                return(Converters.BigEndianToHexString(qsyrupwdCallParameters[0].ParameterValue, 17, 16));

            case PASSWORD_HASH_DES:     // Composed DES hash (PW_TOKENa XOR PW_TOKENb):
                return(Converters.BigEndianToHexString(Converters.UInt64ToBigEndian(Converters.BigEndianToUInt64(qsyrupwdCallParameters[0].ParameterValue, 1, 8) ^ Converters.BigEndianToUInt64(qsyrupwdCallParameters[0].ParameterValue, 9, 8))));

            case PASSWORD_HASH_SECONDDES:     // Second DES password token (PW_TOKENb)
                return(Converters.BigEndianToHexString(qsyrupwdCallParameters[0].ParameterValue, 9, 8));

            case PASSWORD_HASH_FIRSTDES:     // First DES password (PW_TOKENa)
            default:
                return(Converters.BigEndianToHexString(qsyrupwdCallParameters[0].ParameterValue, 1, 8));
            }
        }