Security in Sybase
Security in Sybase
Topic Advanced security in Sybase IQ FIPS support in Sybase IQ Kerberos authentication support in Sybase IQ Column encryption in Sybase IQ Data types for encrypted columns AES_ENCRYPT function [String] AES_DECRYPT function [String] LOAD TABLE ENCRYPTED clause Working with encrypted columns String comparisons on encrypted text Encryption and decryption examples Setting database options for column encryption Protecting ciphertext data from accidental truncation Preserving ciphertext integrity Preventing misuse of ciphertext
Page 2 2 3 3 5 6 8 9 11 11 12 22 23 23 24
Copyright 2010 by Sybase, Inc. All rights reserved. Sybase trademarks can be viewed at the Sybase trademarks page at http://www.sybase.com/detail?id=1011207. Sybase and the marks listed are trademarks of Sybase, Inc. indicates registration in the United States of America. Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the U.S. and other countries. Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. All other company and product names mentioned may be trademarks of the respective companies with which they are associated.
FIPS also requires this registry setting, which is set automatically by the Sybase IQ installation utility:
[HKEY_LOCAL_MACHINE\SOFTWARE\Certicom\libsb] "expectedtag"=hex:5b,0f,4f,a6,e2,4a,ef,3b,44,07,05,2e, b0,49,02,71,1f,d9,91,b6
For more information about using FIPS and RSA encryption, see Transportlayer security and Keeping your data secure in SQL Anywhere 11.0.1 > SQL Anywhere Server Database Administration > Security.
Sybase IQ
Users must be specifically licensed to use the encrypted column functionality of the Sybase IQ Advanced Security Option described in this product documentation. Certain database options affect column encryption. Before using this feature, see Setting database options for column encryption on page 22.
Definitions
A number used to encrypt or decrypt data. Symmetric-key encryption systems use the same key for both encryption and decryption. Asymmetric-key systems use one key for encryption and a different (but mathematically related) key for decryption. The Sybase IQ interfaces accept character strings as keys. Pronounced reign dahl. A specific encryption algorithm that supports a variety of key and block sizes. The algorithm was designed to use simple whole-byte operations and thus is relatively easy to implement in software.
Rijndael
algorithm for the protection of sensitive (but unclassified) electronic data. AES adopted the Rijndael algorithm with restrictions on the block sizes and key lengths. AES is the algorithm supported by Sybase IQ.
The first parameter of the AES_ENCRYPT function must be one of these supported data types:
CHAR VARCHAR TINYINT SMALLINT INTEGER BIGINT BIT BINARY VARBINARY UNSIGNED INT UNSIGNED BIGINT NUMERIC FLOAT REAL DOUBLE DECIMAL DATE TIME DATETIME TIMESTAMP SMALLDATETIME
The LOB data type is not currently supported for Sybase IQ column encryption.
Preserving data types
Sybase IQ ensures that the original data type of the plaintext is preserved when decrypting data, if the AES_DECRYPT function is given the data type as a parameter, or is within a CAST function. Sybase IQ compares the target data type of the CAST with the data type of the originally encrypted data. If the two data types do not match, a -1001064 error is returned with details about the original and target data types. For example, given an encrypted VARCHAR(1) value and this valid decryption statement:
SELECT AES_DECRYPT ( thecolumn, theKey, VARCHAR(1) ) FROM thetable
Sybase IQ
This data type check is made only when supplied. Without the CAST or the data type parameter, the query returns the ciphertext as binary data.
Note When using the AES_ENCRYPT function on literal constants, as in this
statement:
INSERT INTO t (cipherCol) VALUES (AES_ENCRYPT (1, key))
be aware that the data type of 1 is ambiguous. The data type of 1 can be a TINYINT, SMALLINT, INTEGER, UNSIGNED INT, BIGINT, UNSIGNED BIGINT or possibly other data types. Sybase recommends explicit use of the CAST function to resolve any potential ambiguity, as in:
INSERT INTO t (cipherCol) VALUES ( AES_ENCRYPT (CAST (1 AS UNSIGNED INTEGER), key))
Explicitly converting the data type using the CAST function when encrypting data prevents problems using the CAST function when the data is decrypted. There is no ambiguity if the data being encrypted is from a column or if the encrypted data was inserted by LOAD TABLE.
Encrypts the specified values using the supplied encryption key, and returns a VARBINARY or LONG VARBINARY.
AES_ENCRYPT( string-expression, key ) string-expression
The data to be encrypted. For a list of supported data types, see Data types for encrypted columns on page 5. Binary values can also be passed to AES_ENCRYPT. This parameter is case-sensitive, even in case-insensitive databases.
key
The encryption key used to encrypt the string-expression. To obtain the original value, you must also use the same key to decrypt the value. This parameter is case sensitive, even in case-insensitive databases.
As with most passwords, it is best to choose a key value that is difficult to guess. Sybase recommends that you choose a value for your key that is at least 16 characters long, contains a mix of uppercase and lowercase letters, and includes numbers and special characters. You need this key each time you want to decrypt the data.
Warning! Protect your key; store a copy of your key in a safe location. If you lose your key, encrypted data becomes completely inaccessible and unrecoverable. Usage
AES_ENCRYPT returns a VARBINARY value, which is at most 31 bytes longer than the input string-expression. The value returned by this function is the ciphertext, which is not human-readable. You can use the AES_DECRYPT function to decrypt a string-expression that was encrypted with the AES_ENCRYPT function. To successfully decrypt a string-expression, use the same encryption key and algorithm used to encrypt the data. If you specify an incorrect encryption key, an error is generated.
If you are storing encrypted values in a table, the column should be of data type
VARBINARY or VARCHAR, and greater than or equal to 32 bytes, so that
character set conversion is not performed on the data. (Character set conversion would prevent decryption of the data.) If the length of the VARBINARY or VARCHAR column is less than 32 bytes, then the AES_DECRYPT function returns an error. The result data type of an AES_ENCRYPT function may be a LONG VARBINARY. If you use AES_ENCRYPT in a SELECT INTO statement, you must have an Unstructured Data Analytics Option license, or use CAST and set AES_ENCRYPT to the correct data type and size. For additional details and usage information, see REPLACE function [String] in Chapter 4, SQL Functions in Reference: Building Blocks, Tables, and Procedures.
Standards and compatibility See also SQL
Vendor extension to ISO/ANSI SQL grammar Not supported by Adaptive Server Enterprise
Sybase
Example
See Encryption and decryption examples on page 12 for an example of the use of the AES_ENCRYPT function.
Sybase IQ
Decrypts the string using the supplied key, and returns, by default, a VARBINARY or LONG VARBINARY, or the original plaintext type.
AES_DECRYPT( string-expression, key [, data-type ] ) string-expression
The string to be decrypted. Binary values can also be passed to this function. This parameter is case sensitive, even in caseinsensitive databases.
key
The encryption key required to decrypt the string-expression. To obtain the original value that was encrypted, the key must be the same encryption key that was used to encrypt the string-expression. This parameter is case-sensitive, even in case-insensitive databases.
Warning! Protect your key; store a copy of your key in a safe location. If you lose your key, the encrypted data becomes completely inaccessible and unrecoverable. data-type This optional parameter specifies the data type of the decrypted
string-expression and must be the same data type as the original plaintext. If you do not use a CAST statement while inserting data using the AES_ENCRYPT function, you can view the same data using the AES_DECRYPT function by passing VARCHAR as the data-type. If you do not pass data-type to AES_DECRYPT, VARBINARY data type is returned.
Usage
You can use the AES_DECRYPT function to decrypt a string-expression that was encrypted with the AES_ENCRYPT function. This function returns a VARBINARY or LONG VARBINARY value with the same number of bytes as the input string, if no data type is specified. Otherwise, the specified data type is returned. To successfully decrypt a string-expression, you must use the same encryption key that was used to encrypt the data. An incorrect encryption key returns an error.
SQL
Vendor extension to ISO/ANSI SQL grammar Not supported by Adaptive Server Enterprise
Sybase
AES_ENCRYPT function [String] on page 6 Encryption and decryption examples on page 12 LOAD TABLE ENCRYPTED clause on page 9
Example
This example decrypts the password of a user from the user_info table:
SELECT AES_DECRYPT(user_pwd, '8U3dkA', CHAR(100)) FROM user_info;
See Example on page 10. For full syntax, see LOAD TABLE statement in Chapter 1, SQL Statements of Reference: Statements and Options.
Syntax Parameters | ENCRYPTED(data-type key-string [, algorithm-string ] ) data-type The data type that the input file field should be converted to as input to the AES_ENCRYPT function. For supported data types, see Data types for encrypted columns on page 5. data-type should be the same data type as the data type of the output of the AES_DECRYPT function. See AES_DECRYPT function [String] on page 8. key-string The encryption key used to encrypt the data. This key must be a string literal. To obtain the original value, you must use the same key to decrypt the value. This parameter is case sensitive, even in case-insensitive databases.
As with most passwords, it is best to choose a key value that cannot be easily guessed. Sybase recommends that you choose a value for your key that is at least 16 characters long, contains a mix of uppercase and lowercase letters, and includes numbers and special characters. You will need this key each time you want to decrypt the data.
Warning! Protect your key; store a copy of your key in a safe location. A lost key results in the encrypted data becoming completely inaccessible, from which there is no recovery.
Sybase IQ
algorithm-string The algorithm used to encrypt the data. This parameter is optional, but data must be encrypted and decrypted using the same algorithm. Currently, AES is the default, as it is the only supported algorithm. AES is a block encryption algorithm chosen as the new Advanced Encryption Standard (AES) for block ciphers by the National Institute of Standards and Technology (NIST). Usage
The ENCRYPTED column specification allows you to specify the encryption key and, optionally, the algorithm to use to encrypt the data that is loaded into the column. The target column for this load should be VARBINARY. Specifying other data types returns an error. AES_ENCRYPT function [String] on page 6 AES_DECRYPT function [String] on page 8 Encryption and decryption examples on page 12
LOAD TABLE table_name ( plaintext_column_name, a_ciphertext_column_name NULL('nil') ENCRYPTED(varchar(6),'tHefiRstkEy') , another_encrypted_column ENCRYPTED(bigint,'thEseconDkeY','AES') ) FROM '/path/to/the/input/file' FORMAT ascii DELIMITED BY ';' ROW DELIMITED BY '\0xa' QUOTES OFF ESCAPES OFF
See also
Example
where the format of the input file for the LOAD TABLE statement is:
a;b;c; d;e;f; g;h;i;
10
Sybase IQ
11
This example of the AES_ENCRYPT and AES_DECRYPT functions is written in commented SQL.
This example of aes_encrypt and aes_decrypt function use is presented three parts: Part I: Preliminary description of target tables and users as DDL Part II: Example schema changes motivated by introduction of encryption Part III: Use of views and stored procedures to protect encryption keys
-----------
Part I: Define target tables and users Assume two classes of user, represented here by the instances PrivUser and NonPrivUser, assigned to groups reflecting differing privileges. The initial state reflects the schema prior to the introduction of encryption. Set up the starting context: There are two tables with a common key. Some columns contain sensitive data, the remaining columns do not. The usual join column for these tables is sensitiveA. There is a key and a unique index. grant connect to PrivUser identified by 'verytrusted' ; grant connect to NonPrivUser identified by 'lesstrusted' ; grant connect to high_privileges_group ; grant group to high_privileges_group ; grant membership in group high_privileges_group to PrivUser ; grant connect to low_privileges_group ; grant group to low_privileges_group ; grant membership in group low_privileges_group to NonPrivUser ; create table DBA.first_table (sensitiveA char(16) primary key ,sensitiveB numeric(10,0) ,publicC varchar(255) ,publicD date ) ;
12
-There is an implicit unique HG (HighGroup) index enforcing the primary key. create table second_table (sensitiveA char(16) ,publicP integer ,publicQ tinyint ,publicR varchar(64) ) ; create hg index second_A_HG on second_table ( sensitiveA ) ; -TRUSTED users can see the sensitive columns. grant on grant on --select ( sensitiveA, sensitiveB, publicC, publicD ) DBA.first_table to PrivUser ; select ( sensitiveA, publicP, publicQ, publicR ) DBA.second_table to PrivUser ;
Non-TRUSTED users in existing schema need to see sensitiveA to be able to do joins, even though they should not see sensitiveB. grant on grant on select ( sensitiveA, publicC, publicD ) DBA.first_table to NonPrivUser ; select ( sensitiveA, publicP, publicQ, publicR ) DBA.second_table to NonPrivUser ;
--
Non-TRUSTED users can execute queries such as select I.publicC, 3*II.publicQ+1 from DBA.first_table I, DBA.second_table II where I.sensitiveA = II.sensitiveA and I.publicD IN ( '2006-01-11' ) ;
--
and select count(*) from DBA.first_table I, DBA.second_table II where I.sensitiveA = II.sensitiveA and SUBSTR(I.sensitiveA,4,3) BETWEEN '345' AND '456' ;
--
But only TRUSTED users can execute the query select I.sensitiveB, 3*II.publicQ+1 from DBA.first_table I, DBA.second_table II where I.sensitiveA = II.sensitiveA and I.publicD IN ( '2006-01-11' ) ;
Sybase IQ
13
--------
Part II: Change the schema in preparation for encryption The DBA introduces encryption as follows: For applicable tables, the DBA changes the schema, adjusts access permissions, and updates existing data. The encryption keys used are hidden in a subsequent step.
-------------------------------
DataLength comparison for length of varbinary encryption result (units are Bytes): PlainText CipherText 0 16 32 48 64 80 96 112 128 144 160 176 192 208 224 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240 Corresponding Numeric Precisions
The integer data types tinyint, small int, integer, and bigint are varbinary(32) ciphertext. The exact relationship is DATALENGTH(ciphertext) = (((DATALENGTH(plaintext)+ 15) / 16) + 1) * 16 For the first table, the DBA chooses to preserve both the plaintext and ciphertext forms. This is not typical and should only be done if the database files are also encrypted. Take away NonPrivUser's access to column sensitiveA and transfer access to the ciphertext version.
14
-----
Put a unique index on the ciphertext column. The ciphertext itself is indexed. NonPrivUser can select the ciphertext and use it. PrivUser can still select either form (without paying decrypt costs). revoke select ( sensitiveA ) on DBA.first_table from NonPrivUser ; alter table DBA.first_table add encryptedA varbinary(32) ; grant select ( encryptedA ) on DBA.first_table to PrivUser ; grant select ( encryptedA ) on DBA.first_table to NonPrivUser ; create unique hg index first_A_unique on first_table ( encryptedA ) ; update DBA.first_table set encryptedA = aes_encrypt(sensitiveA, 'seCr3t') where encryptedA is null ; commit
--
Now change column sensitiveB. alter table DBA.first_table add encryptedB varbinary(32) ; grant select ( encryptedB ) on DBA.first_table to PrivUser ; create unique hg index first_B_unique on first_table ( encryptedB ) ; update DBA.first_table set encryptedB = aes_encrypt(sensitiveB, 'givethiskeytonoone') where encryptedB is null ; commit
---
For the second table, the DBA chooses to keep only the ciphertext. This is more typical and encrypting the database files is not required. revoke select ( sensitiveA ) on DBA.second_table from NonPrivUser ; revoke select ( sensitiveA ) on DBA.second_table from PrivUser ; alter table DBA.second_table add encryptedA varbinary(32) ; grant select ( encryptedA ) on DBA.second_table to PrivUser ; grant select ( encryptedA ) on DBA.second_table to NonPrivUser ; create unique hg index second_A_unique on second_table ( encryptedA ) ; update DBA.second_table set encryptedA = aes_encrypt(sensitiveA, 'seCr3t') where encryptedA is null ; commit alter table DBA.second_table drop sensitiveA ;
Sybase IQ
15
-----
The following types of queries are permitted at this point, before changes are made for key protection: Non-TRUSTED users can equi-join on ciphertext; they can also select the binary, but have no way to interpret it. select I.publicC, 3*II.publicQ+1 from DBA.first_table I, DBA.second_table II where I.encryptedA = II.encryptedA and I.publicD IN ( '2006-01-11' ) ;
----------
Ciphertext-only access rules out general predicates and expressions. The following query does not return meaningful results. NOTE: These four predicates can be used on the varbinary containing ciphertext: = (equality) <> (inequality) IS NULL IS NOT NULL select count(*) from DBA.first_table I, DBA.second_table II where I.encryptedA = II.encryptedA and SUBSTR(I.encryptedA,4,3) BETWEEN '345' AND '456' ;
----
The TRUSTED user still has access to the plaintext columns that were retained. Therefore, this user does not need to call aes_decrypt and does not need the key. select count(*) from DBA.first_table I, DBA.second_table II where I.encryptedA = II.encryptedA and SUBSTR(I.sensitiveA,4,3) BETWEEN '345' AND '456' ;
16
----------
Part III: Protect the encryption keys This section illustrates how to grant access to the plaintext, but still protect the keys. For the first table, the DBA elected to retain the plaintext columns. Therefore, the following view has the same capabilities as the trusted user above. Assume group_member is being used for additional access control. NOTE: In this example, NonPrivUser still has access to the ciphertext encrypted in the base table. create view DBA.a_first_view (sensitiveA, publicC, publicD) as select IF group_member('high_privileges_group',user_name()) = 1 THEN sensitiveA ELSE NULL ENDIF, publicC, publicD from first_table ; grant select on DBA.a_first_view to PrivUser ; grant select on DBA.a_first_view to NonPrivUser ;
-----
For the second table, the DBA did not keep the plaintext. Therefore, aes_decrypt calls must be used in the view. IMPORTANT: Hide the view definition with ALTER VIEW, so that no one can discover the key. create view DBA.a_second_view (sensitiveA,publicP,publicQ,publicR) as select IF group_member('high_privileges_group',user_name()) = 1 THEN aes_decrypt(encryptedA,'seCr3t', char(16)) ELSE NULL ENDIF, publicP, publicQ, publicR from second_table ;
Sybase IQ
17
alter view DBA.a_second_view set hidden ; grant select on DBA.a_second_view to PrivUser ; grant select on DBA.a_second_view to NonPrivUser ; ---Likewise, the key used for loading can be protected in a stored procedure. By hiding the procedure (just as the view is hidden), no one can see the keys. create procedure load_first_proc(@inputFileName varchar(255), @colDelim varchar(4) default '$', @rowDelim varchar(4) default '\n') begin execute immediate with quotes 'load table DBA.second_table (encryptedA encrypted(char(16),' || '''' || 'seCr3t' || '''' || '),publicP,publicQ,publicR) ' || ' from ' || '''' || @inputFileName || '''' || ' delimited by ' || '''' || @colDelim || '''' || ' row delimited by ' || '''' || @rowDelim || '''' || ' quotes off escapes off' ; end ; alter procedure DBA.load_first_proc set hidden ; -Call the load procedure using the following syntax: call load_first_proc('/dev/null', '$', '\n') ; ----Below is a comparison of several techniques for protecting the encryption keys by using user-defined functions (UDFs), other views, or both. The first and the last alternatives offer maximum performance. The second_table is secured as defined earlier.
18
---
Alternative 1: This baseline approach relies on restricting access to the entire view. create view DBA.second_baseline_view(sensitiveA,publicP,publicQ,publicR) as select IF group_member('high_privileges_group',user_name()) = 1 THEN aes_decrypt(encryptedA,'seCr3t', char(16)) ELSE NULL ENDIF, publicP, publicQ, publicR from DBA.second_table ; alter view DBA.second_baseline_view set hidden ; grant select on DBA.second_baseline_view to NonPrivUser ; grant select on DBA.second_baseline_view to PrivUser ;
-Alternative 2: -- Place the encryption function invocation within a user-defined -function (UDF). -- Hide the definition of the UDF. Restrict the UDF permissions. -- Use the UDF in a view that handles the remainder of the security -and business logic. -- Note: The view itself does not need to be hidden. create function DBA.second_decrypt_function(IN datum varbinary(32)) RETURNS char(16) DETERMINISTIC BEGIN RETURN aes_decrypt(datum,'seCr3t', char(16)); END ; grant execute on DBA.second_decrypt_function to PrivUser ; alter function DBA.second_decrypt_function set hidden ;
Sybase IQ
19
create view DBA.second_decrypt_view(sensitiveA,publicP,publicQ,publicR) as select IF group_member('high_privileges_group',user_name()) = 1 THEN second_decrypt_function(encryptedA) ELSE NULL ENDIF, publicP, publicQ, publicR from DBA.second_table ; grant select on DBA.second_decrypt_view to NonPrivUser ; grant select on DBA.second_decrypt_view to PrivUser ; -------Alternative 3: Sequester only the key selection in a user-defined function. This function could be extended to support selection of any number of keys. This UDF is also hidden and has restricted execute privileges. Note: Any view that uses this UDF therefore does not compromise the key values. create function DBA.second_key_function() RETURNS varchar(32) DETERMINISTIC BEGIN return 'seCr3t' ; END grant execute on DBA.second_key_function to PrivUser ; alter function DBA.second_key_function set hidden ;
20
create view DBA.second_key_view(sensitiveA,publicP,publicQ,publicR) as select IF group_member('high_privileges_group',user_name()) = 1 THEN aes_decrypt(encryptedA,second_key_function(), char(16)) ELSE NULL ENDIF, publicP, publicQ, publicR from DBA.second_table ; grant select on DBA.second_key_view to NonPrivUser ; grant select on DBA.second_key_view to PrivUser ; ------Alternative 4: The recommended alternative is to separate the security logic from the business logic by dividing the concerns into two views. Only the security logic view needs to be hidden. Note: The performance of this approach is similar to that of the first alternative. create view DBA.second_SecurityLogic_view(sensitiveA,publicP,publicQ,publicR) as select IF group_member('high_privileges_group',user_name()) = 1 THEN aes_decrypt(encryptedA,'seCr3t', char(16)) ELSE NULL ENDIF, publicP, publicQ, publicR from DBA.second_table ; alter view DBA.second_SecurityLogic_view set hidden ;
Sybase IQ
21
create view DBA.second_BusinessLogic_view(sensitiveA,publicP,publicQ,publicR) as select sensitiveA, publicP, publicQ, publicR from DBA.second_SecurityLogic_view ; grant select on DBA.second_BusinessLogic_view to NonPrivUser ; grant select on DBA.second_BusinessLogic_view to PrivUser ; -- End of encryption example Example 2
The ciphertext produced by AES_ENCRYPT differs for two different data types given the same input value and same key. A join of two ciphertext columns that hold encrypted values of two different data types may therefore not return identical results. For example, assume:
CREATE TABLE tablea(c1 int, c2 smallint); INSERT INTO tablea VALUES (100,100);
The value AES_ENCRYPT(c1, 'key') differs from AES_ENCRYPT(c2,'key') and the value AES_ENCRYPT(c1,'key') differs from AES_ENCRYPT(100,'key'). To resolve this issue, cast the input of AES_ENCRYPT to the same data type. For example, the results of these code fragments are the same:
AES_ENCRYPT(c1, 'key'); AES_ENCRYPT(CAST(c2 AS INT), 'key'); AES_ENCRYPT(CAST(100 AS INT), 'key');
22
When STRING_RTRUNCATION is ON (the default), the engine raises an error whenever a string would be truncated during a load, insert, update, or SELECT INTO operation. This is ISO/ANSI SQL behavior and is a recommended practice. When explicit truncation is required, use a string expression such as LEFT, SUBSTRING, or CAST. Setting STRING_RTRUNCATION OFF forces silent truncation of strings. The AES_DECRYPT function also checks input ciphertext for valid data length, and checks text output to verify both the resulting data length and the correctness of the supplied key. (If the data type argument is supplied, the data type is checked as well.)
When ASE_BINARY_DISPLAY is OFF (the default), the system leaves binary data unmodified, and in its raw binary form. When ASE_BINARY_DISPLAY is ON, the system converts binary data into its hexadecimal string display representation. Temporarily set the option to ON only if you need data to display to an end user or if you need to export the data to another external system, where raw binary could become altered in transit.
Sybase IQ
23
Setting CONVERSION_MODE to 1 restricts implicit conversion of binary data types to any other nonbinary data type on INSERT and UPDATE commands, and in queries. The restrict binary conversion mode also applies to LOAD TABLE default values and CHECK constraint. The CONVERSION_MODE option default value of 0 maintains the implicit conversion behavior of binary data types in versions of Sybase IQ earlier than 12.7. See CONVERSION_MODE option in Chapter 2, Database Options of Reference: Statements and Options.
24