Bug #8669 AES_DECRYPT fails on null values

Submitted: 22 Feb 2005 5:56 Modified: 10 Mar 2005 18:16
Reporter: Ralf Hauser Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S2 (Serious)
Version:mysqld Ver 4.0.21-log for pc-linux-gnu OS:Any (*)
Assigned to: Igor Babaev CPU Architecture:Any

[22 Feb 2005 5:56] Ralf Hauser
Description:
As per http://bugs.mysql.com/bug.php?id=8564, when selecting a list of two values, if I order the list, the values are different than when just retrieved.

What you will see with the below code:
wrong:
  1:testSubj
  2:testSubj
Now second round with correct result - selDraftStmt: 
  1:testSubj
  2:null

How to repeat:
            Statement stmt = null;
            ResultSet rs = null;

            try {
                stmt = this.conn.createStatement(
                        java.sql.ResultSet.TYPE_FORWARD_ONLY,
                        java.sql.ResultSet.CONCUR_UPDATABLE);
                String AESkey = "q2s3d4f5g6o0!;#[";

                stmt.executeUpdate("DROP TABLE IF EXISTS bug8564");
                stmt
                        .executeUpdate("CREATE TABLE bug8564 ("
                                + "msg_id         INT NOT NULL AUTO_INCREMENT UNIQUE, "
                                + "subject        CHAR(255) NOT NULL, PRIMARY KEY (msg_id))");
                stmt.executeUpdate("DROP TABLE IF EXISTS bug8564msg");
                stmt.executeUpdate("CREATE TABLE bug8564msg ("
                        + "msg_id INT NOT NULL AUTO_INCREMENT UNIQUE)");
                stmt
                        .executeUpdate("INSERT INTO bug8564msg (msg_id) VALUES (1);");
                stmt
                        .executeUpdate("INSERT INTO bug8564msg (msg_id) VALUES (2);");

                int autoIncKeyFromApi = -1;

                PreparedStatement insSenderStmt = null;
                insSenderStmt = this.conn.prepareStatement(
                        "INSERT INTO bug8564 (  subject) "
                                + " VALUES (AES_ENCRYPT(?,?));",
                        Statement.RETURN_GENERATED_KEYS);
                insSenderStmt.setString(1, "testSubj"); // subject
                insSenderStmt.setString(2, AESkey);
                log.debug("insSenderStmt: " + //((DelegatingPreparedStatement)
                        insSenderStmt//)
                                //.getDelegate()
                                .toString());
                int retVal = insSenderStmt.executeUpdate();
                rs = insSenderStmt.getGeneratedKeys();
                if (rs.next()) {
                    autoIncKeyFromApi = rs.getInt(1);
                } else {
                    System.out
                            .println("problem with: autoIncKeyFromApi = rs.getInt(1)");
                }
                rs.close();
                System.out.println("Key 1 returned from getGeneratedKeys(): "
                        + autoIncKeyFromApi);
                String aesEncVal = "%EF%BF%AF%13%EF%BF%90%2F%06Wx%03%EF%BE%92%0F%EF%BF%9E%EF%BF%8F%"
                        + "04%EF%BF%A6%EF%BE%82%EF%BE%AEk%17%EF%BF%991%EF%BF%AE%EF%BF%8Cch%EF%BF%B2"
                        + "%EF%BF%97%21%EF%BE%8C%EF%BF%90D%EF%BF%9C%09%3B%EF%BE%90%EF%BF%96n%EF%BE%91"
                        + "%5B%EF%BF%80%0A%3B%EF%BF%BA%EF%BE%BB%3Ad%EF%BF%AB%2F";
                insSenderStmt.setString(1, null);
                insSenderStmt.setString(2, AESkey);
                insSenderStmt = this.conn.prepareStatement(
                        "INSERT INTO bug8564  (subject) VALUES (?);",
                        Statement.RETURN_GENERATED_KEYS);
                insSenderStmt.setString(1, URLDecoder
                        .decode(aesEncVal, "UTF-8"));
                log.debug("insSenderStmt showing bug: "
                        + insSenderStmt.toString());
                retVal = insSenderStmt.executeUpdate();
                rs = insSenderStmt.getGeneratedKeys();
                if (rs.next()) {
                    autoIncKeyFromApi = rs.getInt(1);
                } else {
                    System.out
                            .println("problem with: autoIncKeyFromApi = rs.getInt(1)");
                }
                rs.close();
                System.out.println("Key 2 returned from getGeneratedKeys():"
                        + autoIncKeyFromApi);

                PreparedStatement selDraftStmt = this.conn
                        .prepareStatement("SELECT bug8564.msg_id, AES_DECRYPT(subject,?) AS subject "
                                + " FROM  bug8564 , bug8564msg WHERE "
                                + "bug8564.msg_id = bug8564msg.msg_id "
                                + "ORDER BY msg_id ASC");
                selDraftStmt.setString(1, AESkey);
                System.out.println("selDraftStmt: " + selDraftStmt.toString());
                ResultSet crs = selDraftStmt.executeQuery();
                int i = 0;
                if (crs == null) {
                    log.debug("row set is null!");
                }
                if (!crs.next()) {
                    log.debug("no more results" + i);
                } else {
                    do {
                        i++;
                        System.out.println(crs.getInt("msg_id") + ":"
                                + crs.getString("subject"));
                    } while (crs.next());
                    log.debug(i + " drafts found.");
                }

                selDraftStmt = this.conn
                        .prepareStatement("SELECT bug8564.msg_id, "
                                + " AES_DECRYPT(subject,?) AS subject "
                                + " FROM  bug8564 , bug8564msg WHERE "
                                + "bug8564.msg_id = bug8564msg.msg_id ");
                selDraftStmt.setString(1, AESkey);
                System.out
                        .println("Now second round with correct result - selDraftStmt: "
                                + selDraftStmt.toString());
                crs = selDraftStmt.executeQuery();
                i = 0;
                if (crs == null) {
                    log.debug("row set is null!");
                }
                if (!crs.next()) {
                    log.debug("no more results" + i);
                } else {
                    do {
                        i++;
                        System.out.println(crs.getInt("msg_id") + ":"
                                + crs.getString("subject"));
                    } while (crs.next());
                    log.debug(i + " drafts found.");
                }
                rs.close();

                rs = null;
            } finally {

                if (rs != null) {
                    try {
                        rs.close();
                    } catch (SQLException ex) {
                        // ignore
                    }
                }

                if (stmt != null) {
                    try {
                        stmt.close();
                    } catch (SQLException ex) {
                        // ignore
                    }
                }
            }

Suggested fix:
do not repeat previous value if there is a null value in the string column
[22 Feb 2005 13:07] Aleksey Kishkin
confirm  for 4.0.23. 
I tested also against 4.1.10, it works properly with 4.1.10
(attached a testcase that I used)
[22 Feb 2005 13:08] Aleksey Kishkin
java source of testcase (according to authors description)

Attachment: bug8669.java (application/octet-stream, text), 6.44 KiB.

[8 Mar 2005 20:57] Jim Winstead
This looks like a bug in join processing or optimization. With this test:

create table t1 (id int auto_increment primary key, str char(255) not null);
create table t2 (id int not null unique);
insert into t2 values (1),(2);
insert into t1 (str) values (aes_encrypt('foo', 'bar'));
insert into t1 (str) values ('not valid');
select t1.id, aes_decrypt(str,'bar') from t1, t2 where t1.id = t2.id order by t1.id asc;
drop table t1, t2;

If I remove 'not null' on t1.str, the query returns the expected results.
[9 Mar 2005 8:09] Igor Babaev
For the database presented by Jim:

the following query returns a correst result:

mysql> SELECT t1.id, aes_decrypt(str, 'bar') FROM t1, t2 WHERE t1.id = t2.id;
+----+-------------------------+
| id | aes_decrypt(str, 'bar') |
+----+-------------------------+
|  1 | foo                     |
|  2 | NULL                    |
+----+-------------------------+

While this modification does not:

mysql> SELECT t1.id, aes_decrypt(str, 'bar') FROM t1, t2 WHERE t1.id = t2.id
    ->  ORDER BY t1.id;
+----+-------------------------+
| id | aes_decrypt(str, 'bar') |
+----+-------------------------+
|  1 | foo                     |
|  2 | foo                     |
+----+-------------------------+
[9 Mar 2005 8:16] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/internals/22823
[10 Mar 2005 4:43] Igor Babaev
The function AES_DECRYPT can return NULL value even in the case when its first
argument refers to a column declared as NOT NULL.
This fact was not taken into account.

The fix will appear in releases 4.0.24, 4.1.11, 5.0.3.

ChangeSet
  1.2082 05/03/09 00:15:51 igor@rurik.mysql.com +3 -0
  func_str.result, func_str.test:
    Added a test case for bug #8669.
  item_strfunc.cc:
    Fixed bug #8669.
    Function AES_DECRYPT can return NULL value.
[10 Mar 2005 18:16] Paul DuBois
Noted in 4.0.24, 4.1.11, 5.0.3 changelogs.
[3 Jun 2005 21:29] Ralf Hauser
in a variant, it happens again with non-null values

how to reproduce

insert string "1111" with AES key 1
insert string "2222" with AES key 2

select * with AES_DECRYPT with key 1

result received (wrong)
--------------------------
1111
1111

result expected
------------------
�,о�w�/ %�    (i.e. decryption error)
1
[3 Jun 2005 21:30] Ralf Hauser
forgot to mention - now I am on 4.0.24

Portions of this website are copyright © 2001, 2002 The PHP Group

Page generated in 0.059 sec. using MySQL 8.4.7-u6-cloud

Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the respective copyright holders.
It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.