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); }
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); }
/// <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); }
/// <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); }
/// <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)); } }
/// <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); }
/// <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); }
/// <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)); }
/// <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); }