private static byte[] ConcatenateSecurityBuffers(
            SecurityBuffer[] securityBuffers,
            SecurityBufferType[] targetTypes,
            bool bothReadOnlyAndReadWrite)
        {
            byte[] buf = new byte[0];
            for (int i = 0; i < securityBuffers.Length; i++)
            {
                SecurityBufferType securityBufferType = (securityBuffers[i].BufferType & ~SecurityBufferType.AttrMask);
                bool typeMatch = false;
                for (int j = 0; j < targetTypes.Length; j++)
                {
                    if (securityBufferType == targetTypes[j])
                    {
                        typeMatch = true;
                        break;
                    }
                }
                if (typeMatch)
                {
                    bool skip = !bothReadOnlyAndReadWrite &&
                                (((securityBuffers[i].BufferType & SecurityBufferType.ReadOnly) != 0) ||
                                 ((securityBuffers[i].BufferType & SecurityBufferType.ReadOnlyWithChecksum) != 0));

                    if (!skip && securityBuffers[i].Buffer != null)
                    {
                        buf = ArrayUtility.ConcatenateArrays(buf, securityBuffers[i].Buffer);
                    }
                }
            }
            return(buf);
        }
Beispiel #2
0
        private Authenticator CreateAuthenticator(PrincipalName cname, Realm realm, EncryptionKey subkey = null, AuthorizationData data = null)
        {
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Create authenticator");
            Random r      = new Random();
            int    seqNum = r.Next();

            Authenticator plaintextAuthenticator = new Authenticator
            {
                authenticator_vno  = new Asn1Integer(KerberosConstValue.KERBEROSV5),
                crealm             = realm,
                cusec              = new Microseconds(0),
                ctime              = KerberosUtility.CurrentKerberosTime,
                seq_number         = new KerbUInt32(seqNum),
                cname              = cname,
                subkey             = subkey,
                authorization_data = data
            };

            AuthCheckSum checksum = new AuthCheckSum {
                Lgth = KerberosConstValue.AUTHENTICATOR_CHECKSUM_LENGTH
            };

            checksum.Bnd   = new byte[checksum.Lgth];
            checksum.Flags = (int)(ChecksumFlags.GSS_C_MUTUAL_FLAG | ChecksumFlags.GSS_C_INTEG_FLAG);
            byte[] checkData = ArrayUtility.ConcatenateArrays(BitConverter.GetBytes(checksum.Lgth),
                                                              checksum.Bnd, BitConverter.GetBytes(checksum.Flags));
            plaintextAuthenticator.cksum = new Checksum(new KerbInt32((int)ChecksumType.ap_authenticator_8003), new Asn1OctetString(checkData));

            return(plaintextAuthenticator);
        }
        /// <summary>
        /// Writes a sequence of bytes to the current stream. The data is encrypted first before sending out.
        /// </summary>
        /// <param name="buffer">The buffer to be sent.</param>
        /// <param name="offset">The offset in buffer at which to begin writing to the stream.</param>
        /// <param name="count">The number of bytes to be written.</param>
        /// <exception cref="IOException">Raised when attempting to read from/write to a remote connection which
        /// has been closed</exception>
        /// <exception cref="ArgumentOutOfRangeException">Raised when the offset incremented by count exceeds
        /// the length of buffer</exception>
        public override void Write(byte[] buffer, int offset, int count)
        {
            if (offset > buffer.Length - 1)
            {
                throw new ArgumentOutOfRangeException("offset");
            }

            if (offset + count > buffer.Length)
            {
                throw new ArgumentOutOfRangeException("count");
            }

            byte[] outBuffer = new byte[count];
            Array.Copy(buffer, offset, outBuffer, 0, count);

            // Encrypt message
            SecurityPackageContextStreamSizes streamSizes =
                (SecurityPackageContextStreamSizes)context.QueryContextAttributes("SECPKG_ATTR_STREAM_SIZES");
            SecurityBuffer messageBuffer = new SecurityBuffer(SecurityBufferType.Data, buffer);
            SecurityBuffer headerBuffer  = new SecurityBuffer(
                SecurityBufferType.StreamHeader,
                new byte[streamSizes.Header]);
            SecurityBuffer trailerBuffer = new SecurityBuffer(
                SecurityBufferType.StreamTrailer,
                new byte[streamSizes.Trailer]);
            SecurityBuffer emptyBuffer = new SecurityBuffer(SecurityBufferType.Empty, null);

            context.Encrypt(headerBuffer, messageBuffer, trailerBuffer, emptyBuffer);
            byte[] encryptedMsg = ArrayUtility.ConcatenateArrays(
                headerBuffer.Buffer,
                messageBuffer.Buffer,
                trailerBuffer.Buffer);
            clientStream.Write(encryptedMsg, 0, encryptedMsg.Length);
        }
Beispiel #4
0
        /// <summary>
        /// Construct KERB_VERIFY_PAC_REQUEST structure
        /// </summary>
        /// <param name="serverSignature">
        /// PAC_SIGNATURE_DATA Signature value ([MS-PAC] section 2.8)
        /// for the Server Signature ([MS-PAC] section 2.8.1)
        /// </param>
        /// <param name="kdcSignature">
        /// PAC_SIGNATURE_DATA SignatureType value ([MS-PAC] section 2.8)
        /// for the Key Distribution Center (KDC) Signature ([MS-PAC] section 2.8.1)
        /// </param>
        /// <returns>KERB_VERIFY_PAC_REQUEST structure</returns>
        public static KERB_VERIFY_PAC_REQUEST CreateKerbVerifyPacRequest(
            PAC_SIGNATURE_DATA serverSignature,
            PAC_SIGNATURE_DATA kdcSignature)
        {
            KERB_VERIFY_PAC_REQUEST kerbVerifyPacRequest = new KERB_VERIFY_PAC_REQUEST();

            // ChecksumAndSignature (variable): The PAC_SIGNATURE_DATA Signature value
            // ([MS-PAC] section 2.8) for the Server Signature ([MS-PAC] section 2.8.1) in the PAC.
            // It MUST be followed by the PAC_SIGNATURE_DATA Signature value ([MS-PAC] section 2.8)
            // for the KDC Signature ([MS-PAC] section 2.8.1) in the PAC.
            int checksumAndSignatureLength = serverSignature.Signature.Length + kdcSignature.Signature.Length;

            byte[] checksumAndSignature = new byte[checksumAndSignatureLength];

            checksumAndSignature = ArrayUtility.ConcatenateArrays <byte>(
                serverSignature.Signature,
                kdcSignature.Signature);

            kerbVerifyPacRequest.MessageType          = KERB_VERIFY_PAC_REQUEST_MessageType_Values.Default;
            kerbVerifyPacRequest.SignatureType        = (uint)kdcSignature.SignatureType;
            kerbVerifyPacRequest.SignatureLength      = (uint)kdcSignature.Signature.Length;
            kerbVerifyPacRequest.ChecksumLength       = (uint)serverSignature.Signature.Length;
            kerbVerifyPacRequest.ChecksumAndSignature = checksumAndSignature;

            return(kerbVerifyPacRequest);
        }
 /// <summary>
 /// Covert Smb2TreeConnectRequestPacket to a byte array
 /// </summary>
 /// <returns>The byte array</returns>
 public override byte[] ToBytes()
 {
     return(ArrayUtility.ConcatenateArrays(
                TypeMarshal.ToBytes(this.Header),
                Smb2Utility.MarshalStructure(this.PayLoad),//based on .net marshal
                Buffer != null ? Buffer : new byte[0]));
 }
        /// <summary>
        /// encoding the data with security provider.
        /// </summary>
        /// <param name="data">
        /// a bytes data that contains the data to be encoded with security provider.
        /// </param>
        /// <returns>
        /// a bytes data that contains the encoded data.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// thrown when data is null.
        /// </exception>
        public override byte[] Encode(byte[] data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            // if the SASL security provider is not ready, do not encode.
            if (this.securityContext.NeedContinueProcessing ||
                !this.UsingMessageSecurity)
            {
                return(data);
            }

            byte[] signature        = null;
            byte[] encryptedMessage = null;

            encryptedMessage = this.securityContext.Encrypt(data, out signature);

            // update the signature length
            this.signatureLength = signature.Length;

            return(ArrayUtility.ConcatenateArrays <byte>(
                       new AdtsLdapSaslSecurityHeader(signature, encryptedMessage).ToBytes(),
                       signature,
                       encryptedMessage));
        }
        public static byte[] ProtectSessionKey(byte[] userSessionKey)
        {
            // Take the 16-byte user session key.
            byte[] sessionKey = userSessionKey;

            if (userSessionKey == null)
            {
                return(null);
            }
            // If this is an LM authentication where the session key is only 8 bytes,
            // then zero extend it to 16 bytes.
            else if (userSessionKey.Length < 16)
            {
                sessionKey = ArrayUtility.ConcatenateArrays <byte>(
                    userSessionKey, new byte[16 - userSessionKey.Length]);
            }
            // If the session key is more than 16 bytes, then use only the first 16 bytes.
            else if (userSessionKey.Length > 16)
            {
                sessionKey = ArrayUtility.SubArray <byte>(
                    userSessionKey, userSessionKey.Length - 16);
            }

            // Calculate the one-way hash
            return(new HMACMD5(sessionKey).ComputeHash(SSKeyHash));
        }
        /// <summary>
        /// Get the data to be signed.
        /// </summary>
        /// <param name="securityBuffers">The security buffer to extract the data to be signed</param>
        /// <returns>The data to be signed</returns>
        internal static byte[] GetToBeSignedDataFromSecurityBuffers(SecurityBuffer[] securityBuffers)
        {
            if (securityBuffers == null)
            {
                throw new ArgumentNullException("securityBuffers");
            }
            byte[] message = new byte[0];

            for (int i = 0; i < securityBuffers.Length; i++)
            {
                if (securityBuffers[i] == null)
                {
                    throw new ArgumentNullException("securityBuffers");
                }
                SecurityBufferType securityBufferType = (securityBuffers[i].BufferType & ~SecurityBufferType.AttrMask);

                if (securityBufferType == SecurityBufferType.Data || securityBufferType == SecurityBufferType.Padding)
                {
                    bool skip = (securityBuffers[i].BufferType & SecurityBufferType.ReadOnly) != 0;

                    if (!skip && securityBuffers[i].Buffer != null)
                    {
                        message = ArrayUtility.ConcatenateArrays(message, securityBuffers[i].Buffer);
                    }
                }
            }

            return(message);
        }
        public static _LSAPR_TRUSTED_DOMAIN_AUTH_BLOB CreateTrustedDomainAuthorizedBlob(
            _LSAPR_AUTH_INFORMATION[] currentOutgoingAuthInfos,
            _LSAPR_AUTH_INFORMATION[] previousOutgoingAuthInfos,
            _LSAPR_AUTH_INFORMATION[] currentIncomingAuthInfos,
            _LSAPR_AUTH_INFORMATION[] previousIncomingAuthInfos,
            byte[] sessionKey)
        {
            _LSAPR_TRUSTED_DOMAIN_AUTH_BLOB retVal = new _LSAPR_TRUSTED_DOMAIN_AUTH_BLOB();
            LsaTrustedDomainAuthBlob        blob   = new LsaTrustedDomainAuthBlob();
            Random random = new Random();

            blob.randomData = new byte[BLOB_AUTH_RANDOM_LENGTH]; //leads with 512 bytes of random data
            random.NextBytes(blob.randomData);
            blob.CurrentOutgoingAuthInfos  = MarshalAuthInfos(currentOutgoingAuthInfos);
            blob.PreviousOutgoingAuthInfos = MarshalAuthInfos(previousOutgoingAuthInfos);
            blob.CurrentIncomingAuthInfos  = MarshalAuthInfos(currentIncomingAuthInfos);
            blob.PreviousIncomingAuthInfos = MarshalAuthInfos(previousIncomingAuthInfos);

            blob.CountOutgoingAuthInfos = (uint)(currentOutgoingAuthInfos == null ? 0 : currentOutgoingAuthInfos.Length);
            //blob.ByteOffsetCurrentOutgoingAuthInfo is the sum of sizeof CountOutgoingAuthInfos,
            //sizeof ByteOffsetCurrentOutgoingAuthInfo ,sizeof ByteOffsetCurrentOutgoingAuthInfo;
            blob.ByteOffsetCurrentOutgoingAuthInfo = (uint)(Marshal.SizeOf(blob.CountOutgoingAuthInfos) + Marshal.SizeOf(
                                                                blob.ByteOffsetCurrentOutgoingAuthInfo) + Marshal.SizeOf(blob.ByteOffsetPreviousOutgoingAuthInfo));
            blob.ByteOffsetPreviousOutgoingAuthInfo = (uint)(blob.ByteOffsetCurrentOutgoingAuthInfo
                                                             + blob.CurrentOutgoingAuthInfos.Length);
            blob.CountIncomingAuthInfos = (uint)(currentIncomingAuthInfos == null ? 0 : currentIncomingAuthInfos.Length);
            //same as blob.ByteOffsetCurrentOutgoingAuthInfo
            blob.ByteOffsetCurrentIncomingAuthInfo = (uint)(Marshal.SizeOf(blob.CountIncomingAuthInfos) + Marshal.SizeOf(
                                                                blob.ByteOffsetCurrentIncomingAuthInfo) + Marshal.SizeOf(blob.ByteOffsetPreviousIncomingAuthInfo));
            blob.ByteOffsetPreviousIncomingAuthInfo = (uint)(blob.ByteOffsetCurrentIncomingAuthInfo
                                                             + blob.CurrentIncomingAuthInfos.Length);
            blob.OutgoingAuthInfoSize = (uint)(blob.ByteOffsetPreviousOutgoingAuthInfo
                                               + blob.PreviousOutgoingAuthInfos.Length);
            blob.IncomingAuthInfoSize = (uint)(blob.ByteOffsetPreviousIncomingAuthInfo
                                               + blob.PreviousIncomingAuthInfos.Length);

            byte[] input = ArrayUtility.ConcatenateArrays(
                blob.randomData,
                TypeMarshal.ToBytes(blob.CountOutgoingAuthInfos),
                TypeMarshal.ToBytes(blob.ByteOffsetCurrentOutgoingAuthInfo),
                TypeMarshal.ToBytes(blob.ByteOffsetPreviousOutgoingAuthInfo),
                blob.CurrentOutgoingAuthInfos,
                blob.PreviousOutgoingAuthInfos,
                TypeMarshal.ToBytes(blob.CountIncomingAuthInfos),
                TypeMarshal.ToBytes(blob.ByteOffsetCurrentIncomingAuthInfo),
                TypeMarshal.ToBytes(blob.ByteOffsetPreviousIncomingAuthInfo),
                blob.CurrentIncomingAuthInfos,
                blob.PreviousIncomingAuthInfos,
                TypeMarshal.ToBytes(blob.OutgoingAuthInfoSize),
                TypeMarshal.ToBytes(blob.IncomingAuthInfoSize));

            using (RC4 rc4 = RC4.Create())
            {
                rc4.Key         = sessionKey;
                retVal.AuthBlob = rc4.CreateEncryptor().TransformFinalBlock(input, 0, input.Length);
            }
            retVal.AuthSize = (uint)(retVal.AuthBlob.Length);

            return(retVal);
        }
Beispiel #10
0
 /// <summary>
 /// Encode the struct of SMB_COM_NT_CREATE_ANDX_Request_SMB_Data into the struct of SmbData
 /// </summary>
 protected override void EncodeData()
 {
     byte[] buf = ArrayUtility.ConcatenateArrays(
         BitConverter.GetBytes(this.SmbData.ByteCount),
         this.SmbData.Pad,
         this.SmbData.FileName);
     this.smbDataBlock = TypeMarshal.ToStruct <SmbData>(buf);
 }
 /// <summary>
 /// Covert to a byte array
 /// </summary>
 /// <returns>The byte array</returns>
 public override byte[] ToBytes()
 {
     return(ArrayUtility.ConcatenateArrays(
                TypeMarshal.ToBytes(this.Header),
                TypeMarshal.ToBytes(this.PayLoad),
                Buffer != null ? Buffer : new byte[0],
                Padding));
 }
        public static byte[] AddGssApiTokenHeader(KerberosApRequest request,
                                                  KerberosConstValue.OidPkt oidPkt     = KerberosConstValue.OidPkt.KerberosToken,
                                                  KerberosConstValue.GSSToken gssToken = KerberosConstValue.GSSToken.GSSSPNG)
        {
            byte[] encoded = request.ToBytes();
            byte[] token   = KerberosUtility.AddGssApiTokenHeader(ArrayUtility.ConcatenateArrays(
                                                                      BitConverter.GetBytes(KerberosUtility.ConvertEndian((ushort)TOK_ID.KRB_AP_REQ)), encoded), oidPkt, gssToken);

            return(token);
        }
        /// <summary>
        /// Initialize method is not used for NRPC SSPI.<para/>
        /// NRPC SSPI will negotiate security context in its own RPC call.
        /// </summary>
        /// <param name="inToken">
        /// A token returned from server SSPI;
        /// if it's set to null, indicates to initialize a new client token.
        /// </param>
        /// <exception cref="SspiException">
        /// Thrown when server returned token is invalid.
        /// </exception>
        public override void Initialize(byte[] inToken)
        {
            if (inToken == null)
            {
                //Initialize a new token.
                if (nrpc.Context.SessionKey == null)
                {
                    //Negotiate a session key.
                    NrpcNegotiateFlags clientCapabilities = nrpc.Context.NegotiateFlags;

                    ushort[] nrpcTcpEndpoints = NrpcUtility.QueryNrpcTcpEndpoint(nrpc.Context.PrimaryName);
                    if (nrpcTcpEndpoints == null || nrpcTcpEndpoints.Length == 0)
                    {
                        throw new InvalidOperationException("Server doesn't support NRPC protocol.");
                    }

                    nrpc.BindOverTcp(
                        nrpc.Context.PrimaryName,
                        nrpcTcpEndpoints[0],
                        null,
                        timeout);
                    nrpc.NetrServerReqChallenge(credential.MachineName);
                    nrpc.NetrServerAuthenticate3(
                        credential.AccountName,
                        this.secureChannelType,
                        ref clientCapabilities,
                        credential.Password);
                }

                NL_AUTH_MESSAGE nlAuthMessage = nrpc.CreateNlAuthMessage();
                this.token = ArrayUtility.ConcatenateArrays(
                    BitConverter.GetBytes((uint)nlAuthMessage.MessageType),
                    BitConverter.GetBytes((uint)nlAuthMessage.Flags),
                    nlAuthMessage.Buffer);
                this.needContinueProcessing = true;
            }
            else
            {
                this.token = null;
                this.needContinueProcessing = false;

                NL_AUTH_MESSAGE nlAuthMessage = new NL_AUTH_MESSAGE();
                int             offset        = 0;
                nlAuthMessage.MessageType = (MessageType_Values)BitConverter.ToInt32(inToken, offset);
                offset += sizeof(int); // cannot call: Marshal.SizeOf(nlAuthMessage.MessageType);
                nlAuthMessage.Flags = (NL_AUTH_MESSAGE_Flags_Value)BitConverter.ToUInt32(inToken, offset);
                offset += sizeof(NL_AUTH_MESSAGE_Flags_Value);
                nlAuthMessage.Buffer = ArrayUtility.SubArray(inToken, offset, inToken.Length - offset);
                if (!nrpc.ValidateNlAuthMessage(nlAuthMessage))
                {
                    //validate server returned token failed.
                    throw new SspiException("Server returned token is invalid.");
                }
            }
        }
 /// <summary>
 /// Encode the struct of TransData into the byte array in SmbData.Trans_Data
 /// </summary>
 protected override void EncodeTransData()
 {
     this.smbData.Trans_Data = ArrayUtility.ConcatenateArrays(
         TypeMarshal.ToBytes(this.transData.OutputBufferSize),
         TypeMarshal.ToBytes(this.transData.InputBufferSize),
         TypeMarshal.ToBytes(this.transData.MaximumInstances),
         TypeMarshal.ToBytes(this.transData.CurrentInstances),
         TypeMarshal.ToBytes(this.transData.PipeNameLength),
         this.transData.Pad,
         this.transData.PipeName);
 }
Beispiel #15
0
        /// <summary>
        /// Client initialize with server token
        /// </summary>
        /// <param name="serverToken">Server token</param>
        private void ClientInitialize(byte[] serverToken)
        {
            KerberosApResponse apRep = this.GetApResponseFromToken(serverToken, KerberosConstValue.GSSToken.GSSAPI);

            this.VerifyApResponse(apRep);

            token = null;
            if ((contextAttribute & ClientSecurityContextAttribute.DceStyle) == ClientSecurityContextAttribute.DceStyle)
            {
                KerberosApResponse apResponse = this.CreateApResponse(null);

                var apBerBuffer = new Asn1BerEncodingBuffer();

                if (apResponse.ApEncPart != null)
                {
                    // Encode enc_part
                    apResponse.ApEncPart.BerEncode(apBerBuffer, true);

                    EncryptionKey key = this.Context.ApSessionKey;

                    if (key == null || key.keytype == null || key.keyvalue == null || key.keyvalue.Value == null)
                    {
                        throw new ArgumentException("Ap session key is not valid");
                    }

                    // Encrypt enc_part
                    EncryptionType eType      = (EncryptionType)key.keytype.Value;
                    byte[]         cipherData = KerberosUtility.Encrypt(
                        eType,
                        key.keyvalue.ByteArrayValue,
                        apBerBuffer.Data,
                        (int)KeyUsageNumber.AP_REP_EncAPRepPart);
                    apResponse.Response.enc_part = new EncryptedData(new KerbInt32((int)eType), null, new Asn1OctetString(cipherData));
                }

                // Encode AP Response
                apResponse.Response.BerEncode(apBerBuffer, true);

                if ((this.Context.ChecksumFlag & ChecksumFlags.GSS_C_DCE_STYLE) == ChecksumFlags.GSS_C_DCE_STYLE)
                {
                    // In DCE mode, the AP-REP message MUST NOT have GSS-API wrapping.
                    // It is sent as is without encapsulating it in a header ([RFC2743] section 3.1).
                    this.token = apBerBuffer.Data;
                }
                else
                {
                    this.token = KerberosUtility.AddGssApiTokenHeader(ArrayUtility.ConcatenateArrays(
                                                                          BitConverter.GetBytes(KerberosUtility.ConvertEndian((ushort)TOK_ID.KRB_AP_REP)),
                                                                          apBerBuffer.Data));
                }
            }

            this.needContinueProcessing = false;      // SEC_E_OK;
        }
 /// <summary>
 /// Wrap a length before the buffer.
 /// </summary>
 /// <param name="buffer">The buffer to be wrapped.</param>
 /// <param name="isBigEndian">Specify if the length is Big-Endian.</param>
 /// <returns>The buffer added length.</returns>
 internal static byte[] WrapLength(byte[] buffer, bool isBigEndian)
 {
     if (isBigEndian)
     {
         return(ArrayUtility.ConcatenateArrays(
                    BitConverter.GetBytes(KileUtility.ConvertEndian((uint)buffer.Length)), buffer));
     }
     else
     {
         return(ArrayUtility.ConcatenateArrays(BitConverter.GetBytes(buffer.Length), buffer));
     }
 }
Beispiel #17
0
        /// <summary>
        /// Writes a sequence of bytes to the current stream. The data is encrypted first before sending out.
        /// </summary>
        /// <param name="buffer">The buffer to be sent.</param>
        /// <param name="offset">The offset in buffer at which to begin writing to the stream.</param>
        /// <param name="count">The number of bytes to be written.</param>
        /// <exception cref="IOException">Raised when attempting to read from/write to a remote connection which
        /// has been closed</exception>
        /// <exception cref="ArgumentOutOfRangeException">Raised when the offset incremented by count exceeds
        /// the length of buffer</exception>
        public override void Write(byte[] buffer, int offset, int count)
        {
            if (offset > buffer.Length - 1)
            {
                throw new ArgumentOutOfRangeException("offset");
            }

            if (offset + count > buffer.Length)
            {
                throw new ArgumentOutOfRangeException("count");
            }

            // Get stream attribute
            SecurityPackageContextStreamSizes streamSizes =
                (SecurityPackageContextStreamSizes)context.QueryContextAttributes("SECPKG_ATTR_STREAM_SIZES");

            int         chunckSize = (int)streamSizes.MaximumMessage;
            List <byte> byteList   = new List <byte>();

            while (count > 0)
            {
                int bufferSize = count;
                if (bufferSize > chunckSize)
                {
                    bufferSize = chunckSize;
                }

                byte[] outBuffer = new byte[bufferSize];
                Array.Copy(buffer, offset, outBuffer, 0, bufferSize);
                count  -= bufferSize;
                offset += bufferSize;

                // Encrypt Chunck
                SecurityBuffer messageBuffer = new SecurityBuffer(SecurityBufferType.Data, outBuffer);
                SecurityBuffer headerBuffer  = new SecurityBuffer(
                    SecurityBufferType.StreamHeader,
                    new byte[streamSizes.Header]);
                SecurityBuffer trailerBuffer = new SecurityBuffer(
                    SecurityBufferType.StreamTrailer,
                    new byte[streamSizes.Trailer]);
                SecurityBuffer emptyBuffer = new SecurityBuffer(SecurityBufferType.Empty, null);

                context.Encrypt(headerBuffer, messageBuffer, trailerBuffer, emptyBuffer);
                byte[] encryptedChunck = ArrayUtility.ConcatenateArrays(
                    headerBuffer.Buffer,
                    messageBuffer.Buffer,
                    trailerBuffer.Buffer);
                byteList.AddRange(encryptedChunck);
            }

            byte[] encryptedMsg = byteList.ToArray();
            serverStream.Write(encryptedMsg, 0, encryptedMsg.Length);
        }
        /// <summary>
        /// add received data to buffer.
        /// </summary>
        /// <param name="buffer">
        /// a bytes array that contains the data received from server.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// thrown when data is null.
        /// </exception>
        public void AddReceivedData(byte[] buffer)
        {
            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }

            lock (this.lockObject)
            {
                this.data = ArrayUtility.ConcatenateArrays <byte>(this.data, buffer);
            }
        }
        /// <summary>
        /// do right rotation for a buffer.
        /// </summary>
        /// <param name="buf">buffer to do right rotation</param>
        /// <param name="rrc">right rotation count</param>
        internal static void RotateRight(byte[] buf, int rrc)
        {
            // Assume that the RRC value is 3 and the token before the rotation is
            // {"header" | aa | bb | cc | dd | ee | ff | gg | hh}. The token after
            // rotation would be {"header" | ff | gg | hh | aa | bb | cc | dd | ee },
            // where {aa | bb | cc |...| hh} would be used to indicate the octet sequence.

            rrc = rrc % buf.Length;
            byte[] temp = ArrayUtility.ConcatenateArrays(ArrayUtility.SubArray(buf, buf.Length - rrc),
                                                         ArrayUtility.SubArray(buf, 0, buf.Length - rrc));
            Array.Copy(temp, buf, buf.Length);
        }
        /// <summary>
        /// RC4-HMAC / RC4-HMAC-EXP encryption
        /// </summary>
        /// <param name="key">the secret key</param>
        /// <param name="plain">the to be encrypted plain data</param>
        /// <param name="usage">key usage number</param>
        /// <param name="encryptionType">encryption type</param>
        /// <param name="getToBeSignedDateCallback">
        /// A callback to get to-be-signed data.
        /// The method will use plain-text data directly if this parameter is null.
        /// </param>
        /// <returns>the encrypted data</returns>
        public static byte[] Encrypt(
            byte[] key,
            byte[] plain,
            int usage,
            EncryptionType encryptionType,
            GetToBeSignedDataFunc getToBeSignedDateCallback)
        {
            // check inputs
            if (null == key)
            {
                throw new ArgumentNullException("key");
            }
            if (null == plain)
            {
                throw new ArgumentNullException("plain");
            }

            // add confounder
            byte[] confounderData = CryptoUtility.CreateConfounder(ConstValue.CONFOUNDER_SIZE);
            byte[] plainData      = ArrayUtility.ConcatenateArrays(confounderData, plain);

            // add padding
            plainData = CryptoUtility.AddPadding(plainData, ConstValue.RC4_BLOCK_SIZE);

            // get salt and hash
            byte[] salt    = GetSalt(usage, encryptionType);
            byte[] hash    = CryptoUtility.ComputeMd5Hmac(key, salt);
            byte[] hashExp = GetExpHash(hash, encryptionType);

            byte[] toBeSignedData;
            if (getToBeSignedDateCallback != null)
            {
                toBeSignedData = getToBeSignedDateCallback(plainData);
            }
            else
            {
                toBeSignedData = plainData;
            }

            // get checksum
            byte[] checksum = CryptoUtility.ComputeMd5Hmac(hash, toBeSignedData);

            // get rc4 encryption key
            byte[] rc4Key = CryptoUtility.ComputeMd5Hmac(hashExp, checksum);

            // encrypt
            ICryptoTransform encryptor = CryptoUtility.CreateRc4Encryptor(rc4Key);

            byte[] encryptedData = encryptor.TransformFinalBlock(plainData, 0, plainData.Length);

            // result = checksum + encryptedData
            return(ArrayUtility.ConcatenateArrays(checksum, encryptedData));
        }
        public static void DecryptSecret(_RPC_UNICODE_STRING input, byte[] sessionKey, out _RPC_UNICODE_STRING output)
        {
            output = new _RPC_UNICODE_STRING();
            uint blockLength = CRYPT_BLOCK_LENGTH; //encrypt every 8 bytes
            uint keyLength   = CRYPT_KEY_LENGTH;   //used to compute output key
            uint keyIndex    = 0;                  //the key index of sessionKey

            byte[] buffer      = new byte[blockLength];
            byte[] inputBuffer = new byte[input.Length];

            Buffer.BlockCopy(input.Buffer, 0, inputBuffer, 0, input.Length);
            DesEcbLmDecode(ArrayUtility.SubArray(inputBuffer, 0, (int)blockLength), sessionKey, out buffer);

            //output.Length and version are combined in 8 bytes as the header, each of them occupys 4 bytes.
            output.Length = TypeMarshal.ToStruct <ushort>(buffer);
            uint version = TypeMarshal.ToStruct <uint>(ArrayUtility.SubArray(buffer, 4, sizeof(uint)));

            byte[] outputBuffer = new byte[0];

            if (version != CRYPT_VERSION)
            {
                throw new ArgumentException("failed in checking version.");
            }

            //get the next 7 bytes in sessionKey as the key of DesEcbLm
            //if not enough,
            keyIndex = AdvanceKey(keyIndex);
            uint remaining = input.Length - blockLength;
            uint count     = 1;

            while (remaining > blockLength)
            {
                DesEcbLmDecode(ArrayUtility.SubArray(inputBuffer, (int)(count * blockLength), (int)blockLength),
                               ArrayUtility.SubArray(sessionKey, (int)keyIndex, (int)keyLength), out buffer);
                outputBuffer = ArrayUtility.ConcatenateArrays(outputBuffer, buffer);
                keyIndex     = AdvanceKey(keyIndex);
                count++;
                remaining -= blockLength;
            }
            if (remaining > 0)
            {
                byte[] temp = new byte[blockLength];
                Buffer.BlockCopy(inputBuffer, (int)(count * blockLength), temp, 0, (int)remaining);
                DesEcbLmDecode(temp, ArrayUtility.SubArray(sessionKey, (int)keyIndex, (int)keyLength),
                               out buffer);
                outputBuffer = ArrayUtility.ConcatenateArrays(outputBuffer, buffer);
            }

            output.Buffer        = new ushort[outputBuffer.Length / sizeof(ushort)];
            output.MaximumLength = (ushort)outputBuffer.Length;
            Buffer.BlockCopy(outputBuffer, 0, output.Buffer, 0, outputBuffer.Length);
        }
        public static void EncryptSecret(_RPC_UNICODE_STRING input, byte[] sessionKey, out _RPC_UNICODE_STRING output)
        {
            output = new _RPC_UNICODE_STRING();
            uint blockLength = CRYPT_BLOCK_LENGTH; //encrypt every 8 bytes
            uint keyLength   = CRYPT_KEY_LENGTH;   //used to compute output key
            uint keyIndex    = 0;                  //the key index of sessionKey

            byte[] buffer  = new byte[blockLength];
            uint   version = CRYPT_VERSION; //the version must be 1, defined in TD.

            //copy input.Length and version to buffer, each of them occupys 4 bytes
            //It's the encrypted data's header, when decrypting, the length and version would be decoded in
            //the same format.
            Array.Copy(BitConverter.GetBytes(input.Length), buffer, sizeof(ushort));
            Array.Copy(BitConverter.GetBytes(version), 0, buffer, 4, sizeof(uint));

            byte[] outputBuffer = new byte[buffer.Length];
            DesEcbLmEncode(buffer, sessionKey, out outputBuffer);

            byte[] inputBuffer = new byte[input.Length];
            Buffer.BlockCopy(input.Buffer, 0, inputBuffer, 0, input.Length);

            keyIndex = AdvanceKey(keyIndex);
            uint remaining = input.Length;
            uint count     = 0;

            while (remaining > blockLength)
            {
                DesEcbLmEncode(ArrayUtility.SubArray(inputBuffer, (int)(count * blockLength), (int)blockLength),
                               ArrayUtility.SubArray(sessionKey, (int)keyIndex, (int)keyLength), out buffer);
                outputBuffer = ArrayUtility.ConcatenateArrays(outputBuffer, buffer);
                keyIndex     = AdvanceKey(keyIndex);
                count++;
                remaining -= blockLength;
            }
            if (remaining > 0)
            {
                byte[] temp = new byte[blockLength];
                Buffer.BlockCopy(inputBuffer, (int)(count * blockLength), temp, 0, (int)remaining);
                DesEcbLmEncode(temp, ArrayUtility.SubArray(sessionKey, (int)keyIndex, (int)keyLength),
                               out buffer);
                outputBuffer = ArrayUtility.ConcatenateArrays(outputBuffer, buffer);
            }
            output.Length        = (ushort)outputBuffer.Length;
            output.MaximumLength = (ushort)outputBuffer.Length;
            //output.Length is the length in bytes of output.Buffer
            output.Buffer = new ushort[output.Length / sizeof(ushort)];
            Buffer.BlockCopy(outputBuffer, 0, output.Buffer, 0, output.Length);
        }
Beispiel #23
0
        /// <summary>
        /// Create authenticator for ChecksumType.ap_authenticator_8003
        /// </summary>
        private Authenticator CreateAuthenticator(KerberosTicket ticket, AuthorizationData data, EncryptionKey subkey, ChecksumFlags checksumFlag)
        {
            Authenticator plaintextAuthenticator = CreateAuthenticator(ticket, data, subkey);

            AuthCheckSum checksum = new AuthCheckSum();

            checksum.Lgth  = KerberosConstValue.AUTHENTICATOR_CHECKSUM_LENGTH;
            checksum.Bnd   = new byte[checksum.Lgth];
            checksum.Flags = (int)checksumFlag;
            byte[] checkData = ArrayUtility.ConcatenateArrays(BitConverter.GetBytes(checksum.Lgth),
                                                              checksum.Bnd, BitConverter.GetBytes(checksum.Flags));

            plaintextAuthenticator.cksum = new Checksum(new KerbInt32((int)ChecksumType.ap_authenticator_8003), new Asn1OctetString(checkData));
            return(plaintextAuthenticator);
        }
Beispiel #24
0
        /// <summary>
        /// Encrypts the message and returns another byte array containing message header and encrypted message.
        /// Schannel is not supported.
        /// The returned message will be formatted as follow:
        /// MESSAGE_LENGTH(4 bytes)|MESSAGE|Signature(optional)
        /// </summary>
        /// <param name="messageToBeEncrypted">Message to be encrypted.</param>
        /// <returns>encrypted message</returns>
        public byte[] EncryptMessage(byte[] messageToBeEncrypted)
        {
            byte[] encryptedMessage;
            byte[] signature;

            encryptedMessage = Encrypt(messageToBeEncrypted, out signature);
            int messageLength = encryptedMessage.Length;

            byte[] message = ArrayUtility.ConcatenateArrays(
                BitConverter.GetBytes(messageLength),
                encryptedMessage,
                signature);

            return(message);
        }
        /// <summary>
        /// Create authenticator for AP request or part of PA-DATA for TGS request.
        /// </summary>
        /// <param name="cRealm">This field contains the name of the realm in which the client is registered and in
        /// which initial authentication took place.</param>
        /// <param name="cName">This field contains the name part of the client's principal identifier.</param>
        /// <param name="checksumType">The checksum type selected.</param>
        /// <param name="seqNumber">The current local sequence number.</param>
        /// <param name="flag">The flag set in checksum field of Authenticator.</param>
        /// <param name="subkey">Specify the new subkey used in the following exchange. This field is optional.
        /// This argument can be got with method GenerateKey(ApSessionKey).
        /// This argument can be null. If this argument is null, no subkey will be sent.</param>
        /// <param name="authorizationData">The authentication data of authenticator. This field is optional.
        /// This argument can be generated by method ConstructAuthorizationData. This argument can be null.
        /// If this argument is null, no Authorization Data will be sent.</param>
        /// <param name="key">The key to do checksum.</param>
        /// <param name="checksumBody">The data to compute checksum.</param>
        /// <returns>The created authenticator.</returns>
        private Authenticator CreateAuthenticator(Realm cRealm,
                                                  PrincipalName cName,
                                                  ChecksumType checksumType,
                                                  int seqNumber,
                                                  ChecksumFlags flag,
                                                  EncryptionKey subkey,
                                                  AuthorizationData authorizationData,
                                                  EncryptionKey key,
                                                  byte[] checksumBody)
        {
            Authenticator plaintextAuthenticator = new Authenticator();

            plaintextAuthenticator.authenticator_vno  = new Asn1Integer(ConstValue.KERBEROSV5);
            plaintextAuthenticator.crealm             = cRealm;
            plaintextAuthenticator.cname              = cName;
            plaintextAuthenticator.cusec              = new Microseconds(0);
            plaintextAuthenticator.ctime              = KileUtility.CurrentKerberosTime;
            plaintextAuthenticator.seq_number         = new KerbUInt32(seqNumber);
            plaintextAuthenticator.subkey             = subkey;
            plaintextAuthenticator.authorization_data = authorizationData;

            if (checksumType == ChecksumType.ap_authenticator_8003)
            {
                // compute the checksum
                AuthCheckSum checksum = new AuthCheckSum();
                checksum.Lgth  = ConstValue.AUTHENTICATOR_CHECKSUM_LENGTH;
                checksum.Bnd   = new byte[checksum.Lgth];
                checksum.Flags = (int)flag;
                byte[] checkData = ArrayUtility.ConcatenateArrays(BitConverter.GetBytes(checksum.Lgth),
                                                                  checksum.Bnd,
                                                                  BitConverter.GetBytes(checksum.Flags));
                // in AP request
                plaintextAuthenticator.cksum = new Checksum(new KerbInt32((int)checksumType), new Asn1OctetString(checkData));
            }
            else
            {
                // in TGS PA data
                byte[] checkData = KileUtility.GetChecksum(
                    key.keyvalue.ByteArrayValue,
                    checksumBody,
                    (int)KeyUsageNumber.TGS_REQ_PA_TGS_REQ_adataOR_AP_REQ_Authenticator_cksum,
                    checksumType);

                plaintextAuthenticator.cksum = new Checksum(new KerbInt32((int)checksumType), new Asn1OctetString(checkData));
            }

            return(plaintextAuthenticator);
        }
        /// <summary>
        /// DES-CBC-MD5 / DES-CBC-CRC32 encryption
        /// [RFC 3961, Section 6.2, DES-Based Encryption and Checksum Types]
        ///  "One generates a random confounder of one block, placing it in 'confounder';
        ///  zeros out the 'checksum' field (of length appropriate to exactly hold the checksum
        ///  to be computed); adds the necessary padding; calculates the appropriate checksum
        ///  over the whole sequence, placing the result in 'checksum'; and then encrypts
        ///  using the specified encryption type and the appropriate key."
        /// </summary>
        /// <param name="key">the secret key</param>
        /// <param name="plain">the to be encrypted plain data</param>
        /// <param name="encryptionType">encryption type</param>
        /// <param name="getToBeSignedDateCallback">
        /// A callback to get to-be-signed data.
        /// The method will use plain-text data directly if this parameter is null.
        /// </param>
        /// <returns>the encrypted data</returns>
        public static byte[] Encrypt(
            byte[] key,
            byte[] plain,
            EncryptionType encryptionType,
            GetToBeSignedDataFunc getToBeSignedDateCallback)
        {
            // check inputs
            if (null == key)
            {
                throw new ArgumentNullException("key");
            }
            if (null == plain)
            {
                throw new ArgumentNullException("plain");
            }

            // toBePaddedData = confounderData + emptyChecksumData + plainData
            int checksumSize = GetChecksumSize(encryptionType);

            byte[] toBeEncryptedData = ArrayUtility.ConcatenateArrays(
                CryptoUtility.CreateConfounder(ConstValue.DES_BLOCK_SIZE),
                new byte[checksumSize],
                plain);

            // add padding
            byte[] paddedData = CryptoUtility.AddPadding(toBeEncryptedData, ConstValue.DES_BLOCK_SIZE);

            byte[] toBeSignedData;
            if (getToBeSignedDateCallback != null)
            {
                toBeSignedData = getToBeSignedDateCallback(paddedData);
            }
            else
            {
                toBeSignedData = paddedData;
            }

            // replace the empty checksum with the caculated checksum
            byte[] checksum = CalculateChecksum(toBeSignedData, encryptionType);
            Array.Copy(checksum, 0, paddedData, ConstValue.DES_BLOCK_SIZE, checksum.Length);

            // des-cbc encryption
            byte[]           initialVector = GetInitialVector(key, encryptionType);
            ICryptoTransform encryptor     = CryptoUtility.CreateDesCbcEncryptor(key, initialVector, PaddingMode.None);

            return(encryptor.TransformFinalBlock(paddedData, 0, paddedData.Length));
        }
        /// <summary>
        /// Encrypt in aes128-cts-hmac-sha1-96 or aes256-cts-hmac-sha1-96
        /// </summary>
        /// <param name="key">key data</param>
        /// <param name="plain">plain data to be encrypted</param>
        /// <param name="usage">key usage number</param>
        /// <param name="aesKeyType">aes key type (128bit/256bit)</param>
        /// <param name="getToBeSignedDateCallback">
        /// A callback to get to-be-signed data.
        /// The method will use plain-text data directly if this parameter is null.
        /// </param>
        /// <returns>the encrypted data</returns>
        public static byte[] Encrypt(
            byte[] key,
            byte[] plain,
            int usage,
            AesKeyType aesKeyType,
            GetToBeSignedDataFunc getToBeSignedDateCallback)
        {
            // check inputs
            if (null == key)
            {
                throw new ArgumentNullException("key");
            }
            if (null == plain)
            {
                throw new ArgumentNullException("plain");
            }

            // add confounder data
            byte[] plainData = ArrayUtility.ConcatenateArrays(
                CryptoUtility.CreateConfounder(ConstValue.AES_BLOCK_SIZE),
                plain);

            // use ke key (the encryption key) to encrypt the plain data
            byte[] ke            = AesKey.MakeDerivedKey(key, usage, DerivedKeyType.Ke, aesKeyType);
            byte[] initialVector = new byte[ConstValue.AES_BLOCK_SIZE];
            CipherTextStealingMode aesCtsCrypto = CryptoUtility.CreateAesCtsCrypto(ke, initialVector);

            byte[] encryptedData = aesCtsCrypto.EncryptFinal(plainData, 0, plainData.Length);

            byte[] toBeSignedData;
            if (getToBeSignedDateCallback != null)
            {
                toBeSignedData = getToBeSignedDateCallback(plainData);
            }
            else
            {
                toBeSignedData = plainData;
            }

            // use ki key (the integrity key) to generate checksum
            byte[] ki       = AesKey.MakeDerivedKey(key, usage, DerivedKeyType.Ki, aesKeyType);
            byte[] hmacData = CryptoUtility.ComputeHmacSha1(ki, toBeSignedData);
            hmacData = ArrayUtility.SubArray <byte>(hmacData, 0, ConstValue.HMAC_HASH_OUTPUT_SIZE);

            // result: encryptedData + hmacData
            return(ArrayUtility.ConcatenateArrays(encryptedData, hmacData));
        }
Beispiel #28
0
        /// <summary>
        /// This takes the given message, sign it and returns another byte array containing the original message
        /// and signature, the format of the returned byte array is as follow:
        /// |MESSAGE_LENGTH(4 bytes)|MESSAGE|SIGNATURE|
        /// </summary>
        /// <param name="messageToBeSigned">Message to be signed.</param>
        /// <returns>Signed message and signature, which contains the header.</returns>
        /// <exception cref="SspiException">If sign fail, this exception will be thrown.</exception>
        public byte[] SignMessage(byte[] messageToBeSigned)
        {
            SecurityBuffer messageBuffer   = new SecurityBuffer(SecurityBufferType.Data, messageToBeSigned);
            SecurityBuffer signatureBuffer = new SecurityBuffer(
                SecurityBufferType.Token,
                new byte[NativeMethods.MAX_TOKEN_SIZE]);

            Sign(messageBuffer, signatureBuffer);

            int messageLength = messageBuffer.Buffer.Length;

            byte[] signedMessage = ArrayUtility.ConcatenateArrays(
                BitConverter.GetBytes(messageLength),
                messageBuffer.Buffer,
                signatureBuffer.Buffer);
            return(signedMessage);
        }
 /// <summary>
 /// Calculate salt from key usage number
 /// </summary>
 /// <param name="usage">key usage number</param>
 /// <param name="encryptionType">encryption type</param>
 /// <returns>the caculated salt</returns>
 private static byte[] GetSalt(int usage, EncryptionType encryptionType)
 {
     byte[] keyUsageBytes = BitConverter.GetBytes((int)usage);
     if (encryptionType == EncryptionType.RC4_HMAC)
     {
         return(keyUsageBytes);
     }
     else if (encryptionType == EncryptionType.RC4_HMAC_EXP)
     {
         byte[] constantBytes = Encoding.ASCII.GetBytes(ConstValue.FORTY_BITS);
         return(ArrayUtility.ConcatenateArrays(constantBytes, keyUsageBytes));
     }
     else
     {
         throw new ArgumentException("Unsupported encryption type.");
     }
 }
        /// <summary>
        /// Marshal an array of _LSAPR_AUTH_INFORMATION, alignment is 4
        /// </summary>
        /// <param name="authInfos">a array of _LSAPR_AUTH_INFORMATION</param>
        /// <returns>byte array</returns>
        private static byte[] MarshalAuthInfos(_LSAPR_AUTH_INFORMATION[] authInfos)
        {
            byte[] returnValue = null;
            if (authInfos == null || authInfos.Length == 0)
            {
                return(new byte[0]);
            }

            foreach (_LSAPR_AUTH_INFORMATION authInfo in authInfos)
            {
                returnValue = ArrayUtility.ConcatenateArrays(
                    returnValue,
                    TypeMarshal.ToBytes(authInfo),
                    //alignment is 4 bytes
                    new byte[((authInfo.AuthInfoLength + 3) & ~3) - authInfo.AuthInfoLength]);
            }
            return(returnValue);
        }